' . t('You are missing some Flash content that should appear here! Perhaps your browser cannot display it, or maybe it did not initialize correctly.') . '

'); define('SWFTOOLS_GRANT_ACCESS_TO_PRIVATE_FILES', FALSE); define('SWFTOOLS_GRANT_ACCESS_EXTENSIONS', 'swf flv xml mp3 jpg jpeg png'); define('SWFTOOLS_ALWAYS_ADD_JS', TRUE); define('SWFTOOLS_LIBRARIES', 'sites/all/libraries/'); /** * Used by swftools_profiles_variable_get() to indicate that the requested item is not defined for the specified profile. */ define('SWFTOOLS_PROFILE_UNDEFINED', '__undefined'); /** * Used by functions request player settings to notify that they only need settings that are non-default. * For example, _swftools_wijering4_settings(). */ define('SWFTOOLS_STORED_SETTINGS', 0x0001); /** * Used by functions request player settings to notify that they want the full set, including blanks and defaults. */ define('SWFTOOLS_FULL_SETTINGS', 0x0002); /** * Implementation of hook_init(). */ function swftools_init() { // Add JavaScript that allows other scripts to access movies from the DOM drupal_add_js(drupal_get_path('module', 'swftools') . '/swftools.js'); // Add CSS to enable hiding of accessible controls drupal_add_css(drupal_get_path('module', 'swftools') . '/swftools.css'); } /** * Implementation of hook_menu(). */ function swftools_menu() { // Reset methods cache $methods = swftools_methods_available('', TRUE); // Initialise array $items = array(); // Should this be administer swf tools? $swf_admin = array('administer flash'); $items['admin/settings/swftools'] = array( 'title' => 'SWF Tools', 'description' => 'Settings to control how SWF Tools integrates with Adobe Flash related methods and tools like video players, MP3 players and image viewers.', 'access arguments' => $swf_admin, 'page callback' => 'system_admin_menu_block_page', 'file' => 'system.admin.inc', 'file path' => drupal_get_path('module', 'system'), ); $items['admin/settings/swftools/handling'] = array( 'title' => 'File handling', 'description' => 'Configure how SWF Tools should handle different types of file.', 'access arguments' => $swf_admin, 'weight' => -2, 'page callback' => 'drupal_get_form', 'page arguments' => array('swftools_admin_handling_form'), 'file' => 'swftools.admin.inc', ); $items['swftools/playlist/%'] = array( 'title' => 'SWF Tools playlist', 'page callback' => 'swftools_serve_xml_playlist', 'page arguments' => array(2), 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); $items['admin/settings/swftools/embed'] = array( 'title' => 'Embedding settings', 'description' => 'Set the embedding method that SWF Tools should use, and configure embedding defaults.', 'access arguments' => $swf_admin, 'weight' => -2, 'page callback' => 'drupal_get_form', 'page arguments' => array('swftools_admin_embed_form'), 'file' => 'swftools.admin.inc', ); // If CCK is active then add a link to the CCK formatters if (module_exists('content')) { $items['admin/settings/swftools/cck'] = array( 'title' => 'CCK formatters', 'description' => 'Additional settings to control how SWF Tools should interact with CCK.', 'access arguments' => $swf_admin, 'page callback' => 'drupal_get_form', 'page arguments' => array('swftools_admin_cck_form'), 'file' => 'swftools.admin.inc', ); } // Add SWF Tools status report $items['admin/reports/swftools'] = array( 'title' => 'SWF Tools status', 'description' => 'Get an overview of the status of the SWF Tools module and its supporting files.', 'page callback' => 'swftools_status', 'access arguments' => $swf_admin, 'file' => 'swftools.admin.status.inc', 'weight' => 9, ); // Integrate items from the generic players module $items = array_merge($items, swftools_genericplayers_menu()); // Return array of menu items return $items; } /** * Implementation of hook_perm(). */ function swftools_perm() { return array( 'administer flash', ); } /** * Take an array of play list data and options, and return a markup string. * * @param $playlist_data * A formatted array of data to be used to create the playlist. An appropriate * array can be created from an array of filenames by calling swftools_prepare_playlist_data. * @param $options * An array of options to pass to the call to swf(). * @return * A string of markup to produce the playlist in a flash media player. */ function swf_list($playlist_data, $options = array()) { // Populate methods and othervars with playlist data if (is_array($playlist_data)) { // If action isn't set then set it if (empty($options['methods']['action']) && isset($playlist_data['action'])) { $options['methods']['action'] = $playlist_data['action']; } // If playlist_data isn't set then set it if (empty($options['othervars']['playlist_data'])) { $options['othervars']['playlist_data'] = $playlist_data; } // If playlist filename is set if (isset($playlist_data['filename'])) { $playlist = $playlist_data['filename']; } else { $playlist = ''; } // Produce markup return swf($playlist, $options); } } /** * Return output, which might be embed markup, or pre-flash markup * that includes the appropriate jQuery added to the * * @param $file * The file to be played. If it is a SWF file it will usually be embedded directly. * Use a full URL, a path relative to webroot, or a path relative to the configured files directory. * If an array is passed then the array will be converted to a playlist automatically. * If the file string is a complete url then SWF Tools will pass it along unaltered. If the string * is a partial path then it will either be resolved to the local file system, or to a remote host, * depending whether the swftools_media_url variable is set. * @param $options=>$params * An associative array of variables to set.eg. array('bgcolor'=>'FF00FF') * To set height and width: array('width'=>'200', 'height'=>'120'). However, * as a convenient alternative for the common requirement of just height and width * you can also pass a text string like '200x100'. * If you pass nothing, and the file to play is a .swf, swftools will try and * establish a natural width and height from the actual .swf file that you've * passed into $file. * @param $options=>$flashvars * An associative array of flashvar variables to set. eg. array('playlist'=>'files/my_playlist.xml') * @param $options=>$othervars * An associative array of variables that might be required by the $player or $embed technique. * These values are not output as params or flashvars. * @param $options=>$methods * Explicitly declare an action, player or action by passing an array of * the form: array('action'=>'dosomething','player'=>'withsomething','embed'=>'withthisjavascript'). * These usually default to the administration settings and also you will * usually use a CONSTANT which will be documented further at a later stage. */ function swf($file, $options = array()) { // $time_start = microtime(true); // Initialise any $options array elements that weren't passed by the caller $options += array( 'params' => array(), 'flashvars' => array(), 'othervars' => array(), 'methods' => array(), ); // TODO: We should put SWF Tools own settings somewhere safe in the othervars array // If someone passes a variable from the input filter it could collide. // Maybe put them under #swftools (since the data are properties of swftools?) // A finished item has player, profile, cid, id, file_url, src_path, src // Initialise an empty profile is none was passed $options['othervars'] += array( 'profile' => '', ); /** * Try to use SWF Tools cache. * If the cid is already set then we are on a second pass through swf() because we are * generating a playlist. The first call to swf() calls swf_list() which in turn calls * swf() again. In this instance we don't want to hash the second time round. We want * to cache the output against the cid of the FIRST call so we can pick up the content * on subsequent calls. So we skip attempts at hashing when cid is present, we let the * content be processed, and then we cache at the very end. Now on subsequent calls * we get the "playlist" content immediately. */ if (!isset($options['othervars']['cid']) && ($ret = swftools_fetch_from_cache($file, $options))) { // $time_end = microtime(true); // $time = $time_end - $time_start; // dsm('Used cache in ' . $time); return $ret; } // Ensure id is unique, or assign an id if one isn't set $options = swftools_assign_id($options); // If swf() was called with an array of files, make a playlist and call swf_list() for processing if (is_array($file)) { // Turn the array in to a playlist $playlist_data = swftools_prepare_playlist_data($file, '', isset($options['methods']['action']) ? FALSE : TRUE); // Call swf_list to process the playlist and create the markup $ret = swf_list($playlist_data, $options); // $time_end = microtime(true); // dsm('Generated playlist in '. ($time_end - $time_start)); return $ret; } // Get all the actions, tools and embedding options available to us $all_methods = swftools_methods_available(); // ACTION // Work out what SWF Tools should do with this file // Was an explicit action set in $options['methods']['action'] $action = (isset($options['methods']['action'])) ? $options['methods']['action'] : FALSE; // If an explicit action wasn't set then try to determine an appropriate one using the filename if (!$action) { $action = swftools_get_action($file); } // HTML ALTERNATIVE // If an explicit value wasn't set in $options['othervars']['html_alt'] use a default $html_alt = (isset($options['othervars']['html_alt'])) ? $options['othervars']['html_alt'] : variable_get('swftools_html_alt', SWFTOOLS_DEFAULT_HTML_ALT); // RESOLVE PLAYER AND EMBEDDING // 'resolved' refers to the fact that these are the methods we now intend to use, not /all/ methods available. $resolved_methods = new stdClass(); // PLAYER // Work out what player SWF Tools will need to use for this action // Was an explicit player set in $options['methods']['player'] $player = (isset($options['methods']['player'])) ? $options['methods']['player'] : FALSE; // If an explicit player wasn't set then find out what player is configured for the current action if (!$player) { // Find out what player is assigned to handle the current action $player = swftools_get_player($action, $options['othervars']['profile']); // If still no player assignment then we don't know what to do with this action if (!$player) { // Build an array of descriptions for each possible action $descriptions = array( SWFTOOLS_IMAGE_DISPLAY_LIST=> 'a series of images', SWFTOOLS_FLV_DISPLAY=> 'a single flv file', SWFTOOLS_FLV_DISPLAY_LIST=> 'a series of flv files', SWFTOOLS_MP3_DISPLAY=> 'a single mp3 file', SWFTOOLS_MP3_DISPLAY_LIST=> 'a series of mp3 files', SWFTOOLS_MEDIA_DISPLAY_LIST=> 'a series mixed media files', ); // If we have a matching description for the specified action, create a meaningful message if (isset($descriptions[$action])) { drupal_set_message(t('No player is configured to play ' . $descriptions[$action] . '. Check the SWF Tools file handling settings on the configuration page.'), 'error'); } // Otherwise we have an action that SWF Tools doesn't understand, so create a fallback message else { drupal_set_message(t('No player is configured for the action %action. Check the SWF Tools file handling settings on the configuration page.', array('%action' => $action)), 'error'); } // We couldn't find a player for this content, so fallback to the alternate markup and return return $html_alt; } } // Check that the action / player combination is valid (it should appear in the array of all methods) if (isset($all_methods[$action][$player])) { // If the combination was found, place player information in to $resolved_methods $resolved_methods->player = $all_methods[$action][$player]; } // If the action / player combination doesn't appear then we need to do something else else { // If the action is display an swf directly then assume we have a custom player if ($action == SWFTOOLS_SWF_DISPLAY_DIRECT) { // Assign SWFTOOLS_CUSTOM data in to $resolved_methods $resolved_methods->player = $all_methods[$action][SWFTOOLS_CUSTOM]; $resolved_methods->player['library'] = $player; } // We couldn't find a player for this content, so fallback to the alternate markup and return else { drupal_set_message(t('The combination %player and %action is not valid. Check that the player is available and that it supports the requested action.', array('%player' => $player, '%action' => $action)), 'error', FALSE); return $html_alt; } } // EMBED // Work out what embedding method SWF Tools should use for this content // Was an explicit embedding method set in $options['methods']['embed'] $embed = (isset($options['methods']['embed'])) ? $options['methods']['embed'] : FALSE; // If an explicit embedding method wasn't set then find get the current default if (!$embed) { $embed = variable_get(SWFTOOLS_EMBED_METHOD, SWFTOOLS_NOJAVASCRIPT); } // Place the embedding method information in to $resolved_methods $resolved_methods->embed = $all_methods[SWFTOOLS_EMBED_METHOD][$embed]; // VARIABLES AND PARAMETERS // Put all the variables on a simple object to make internal function calls simpler $vars = new stdClass(); // OTHERVARS // If $options['othervars'] were supplied, add to $vars->othervars $vars->othervars = (is_array($options['othervars'])) ? $options['othervars'] : array(); // PARAMS // $options['params'] could be an associative array, or in 'WIDTHxHEIGHT' format. // If $options were passed to the swf() function then process them if ($options['params']) { // If $options['params'] is an array then just add it to $vars if (is_array($options['params'])) { $vars->params = $options['params']; } // Otherwise see if we can explode the string in to a height and width else { $dimensions = explode('x', $options['params']); if (count($dimensions) == 2) { $vars->params = array( 'width' => $dimensions[0], 'height' => $dimensions[1], ); } } } // FLASHVARS // Flashvars could be passed as an associative array, or as a string in 'a=1&b=2' format // If the flashvars have been passed as an array simply add to $varsa if (is_array($options['flashvars'])) { $vars->flashvars = $options['flashvars']; } // Otherwise parse the flashvars string in to an array else { // Parse the string as if in 'a=1&b=2' format. parse_str($options['flashvars'], $vars->flashvars); } // BASE // Determine a reasonable 'base' directory, if a remote url is set, use that // If file is local, set to the file directory // Was an explicit base path set in $options['params']['base'] $base = (!empty($vars->params['base'])) ? $vars->params['base'] : ''; // If the base path isn't set, or the path is not valid try to find a reasonable alternative if (!$base || !valid_url($base)) { // Retrieve an appropriate base path $base = swftools_get_base(); } // Assign the resulting base path in to $vars->params['base'] $vars->params['base'] = $base; // XML PLAYLIST // Determine if we trying to generate a playlist that needs xml output, and create as required // If $options['othervars']['playlist_data'] is set then we are processing a playlist if (isset($options['othervars']['playlist_data'])) { // Determine the name of the hook that would be used to generate an xml playlist $hook = $resolved_methods->player['name'] . '_swftools_playlist'; // Check that the hook exists - if it doesn't the module doesn't need to create xml output if (module_hook($resolved_methods->player['module'], $hook)) { // Generate a playlist in the files directory $file = swftools_generate_playlist($options['othervars']['playlist_data'], '', $resolved_methods, $vars); // If a file wasn't generated by swftools_generate_playlist then set an error and return alternate markup if (!$file) { drupal_set_message(t('Unable to create xml playlist.'), 'error'); return $html_alt; } } } // CACHING // To try and prevent the xml files from being cached append the time to the filename to try and force it to reload if (variable_get('swftools_playlist_caching', 'here') == 'always') { $nocache = '?nc='. time(); } else { $nocache = ''; } // FILE // Make sure that the file path in $file is valid, and as necessary try to // expand it to a relative url on the local file system, or point to the remote media directory // First we assume that we can just set $file_url to the value in $file $file_url = $file; // But if we are not streaming this file then we might need to process it to get a proper path if (!isset($vars->othervars['stream'])) { // Process to get a url (in src) and expand the path (in src_path) if necessary $source = swftools_src($file); // NOTE : If $file was an empty string then you get src = sites/default/files/site/default/files // If FALSE was returned then the file doesn't exist so return $html_alt if (!$source) { return $html_alt; } // $file might have been changed to reflect a path on the local file system // This happens when the user just supplied a filename and files are being sourced locally // Put $file = $source['src_path'] in case that happened $file = $source['src_path']; // In all cases $file_url is now an absolute, or relative, url to the file that we can use $file_url = $source['src']; } // Attach file_url to othervars so player modules have access if required $vars->othervars['file_url'] = $file_url; // We used to attach things to $vars->params, but then we have to unset them later // So they've been moved to $vars->othervars['src'] and $vars->othervars['src_path'] switch ($player) { // Embedding an swf directly - no player case SWFTOOLS_SWF: $vars->othervars['src_path'] = $file; $vars->othervars['src'] = $file_url; break; // Embedding with a custom player - when would this occur? // TODO: case SWFTOOLS_CUSTOM: and default: look the same? case SWFTOOLS_CUSTOM: $vars->othervars['src_path'] = $resolved_methods->player['library']; $vars->othervars['src'] = base_path() . $vars->othervars['src_path']; break; // Embedding with a standard player default: if ($resolved_methods->player['library']) { $vars->othervars['src_path'] = $resolved_methods->player['library']; $vars->othervars['src'] = base_path() . $vars->othervars['src_path']; } } // Merge default and user defined parameters, with user defined ones taking precedence $vars->params = array_merge(_swftools_params(), $vars->params); // Ask the module implementing the player what flashvars are required, pass // all existing values by reference to allow optional override at the player.module level. if (module_hook($resolved_methods->player['module'], 'swftools_flashvars')) { // Build the name of the function we are going to call $function = $resolved_methods->player['module'] . '_swftools_flashvars'; // Call the function and return the resulting flashvars to the caller $player_flashvars = $function($action, $resolved_methods, $vars, $options['othervars']['profile']); // Merge player flashvars with existing flashvars if (is_array($player_flashvars)) { $vars->flashvars = array_merge($vars->flashvars, $player_flashvars); } } // If $resolved_methods->player['file'] is set we should assign $file_url to a flashvar with that name if (!empty($resolved_methods->player['file'])) { $vars->flashvars[$resolved_methods->player['file']] = $vars->othervars['file_url']; } // If the player requires a specific minimum flash version then assign it to the params if (isset($resolved_methods->player['version'])) { $vars->params['version'] = $resolved_methods->player['version']; } // Call function to set the size of the content swftools_set_size($vars, $resolved_methods->player); // We used to set height and width on $vars->params, but they're not actually params and they were // being unset in individual embedding functions. So we'll move them to $vars->othervars. // We will continue to let users pass the data on $vars->othervars so as not to break existing code. $vars->othervars['height'] = $vars->params['height']; $vars->othervars['width'] = $vars->params['width']; unset($vars->params['height'], $vars->params['width']); // See if anyone wants to alter $vars just before it is output // Note - because $resolved_methods is an object this is also passed by reference in PHP5 drupal_alter('swftools', $vars, $file, $action, $resolved_methods); // Call the embedding code to get the HTML and set the JavaScript if necessary // TODO: Why module_invoke(), why not just make this a theme function too? $embed_markup = module_invoke($resolved_methods->embed['module'], 'swftools_embed', $action, $resolved_methods, $vars, $html_alt); // Call theme function to return completed markup, e.g. add containing div $ret = theme('swftools_embed', $embed_markup, $action, $resolved_methods, $vars, $html_alt); // Cache the result cache_set('swf:'.$options['othervars']['cid'], $ret, 'cache_swftools'); // Return the markup return $ret; } /** * Produce finished markup ready for inserting on the page * * @param $embed_markup * The markup needed to add the swf content to the page * @param $action * The action that is being used, in case the themer wants it * @param $methods * The player and embedding methods being used, in case the themer wants it * @param $vars * The array of othervars, params and flashvars in case the themer wants it * @param $html_alt * The alternate HTML content, in case the themer wants it * @return * An HTML string that generates the output */ function theme_swftools_embed($embed_markup, $action, $methods, $vars, $html_alt) { // Prepare an array of classes to include in the wrapper div $classes[] = 'swftools-wrapper'; $classes[] = str_replace('_', '-', $methods->player['name']); // If the user provided class data already then don't over-rule it if (!empty($vars->othervars['class'])) { $classes[] = $vars->othervars['class']; } // Allow for handling of #prefix and #suffix supplied via $vars->othervars $vars->othervars += array( '#prefix' => '', '#suffix' => '', ); // Wrap $embed_markup with prefix and suffix (e.g. to add accessible controls) $embed_markup = $vars->othervars['#prefix'] . $embed_markup . $vars->othervars['#suffix']; // Return completed markup return '
' . $embed_markup . '
'; } /** * Collect information from all modules about the players and embedding methods available. * * @param $action * Optional parameter to retrieve data only about a specific method. * @param $reset * Optional parameter which if TRUE will reset the method cache and rebuild it. * @return * An array of data describing the available methods. */ function swftools_methods_available($action = NULL, $reset = FALSE) { // Cache methods array as it may be called several times static $methods; // If user has requested the cache to be reset then reset it if ($reset || !isset($methods)) { if (!$reset && ($cached = cache_get('methods', 'cache_swftools'))) { $methods = $cached->data; } else { $methods = module_invoke_all('swftools_methods'); cache_set('methods', $methods, 'cache_swftools'); } } // In case no module is presenting a method for the required action the following line avoids a notice error if ($action) { $methods += array( $action => NULL, ); } // Return results - either for the specific action, or the whole array return $action ? $methods[$action] : $methods; } /** * Converts an array of paramters to JSON and returns them as a string ready for use as a flashvar. * * @param $params * An array of parameters. * @param $attribute * The attribute that the JSON string will be attached to. * @return * A string in the form [attr]={JSON} */ function swftools_json_params(&$params, $attribute = 'swftools') { return $attribute . "='" . drupal_to_js($params) . "'"; } /** * Returns 'true' or 'false' for JavaScript based the supplied value $bool. * * @param $bool * The value that should be cast to true or false. * @return * The string 'true' or 'false' depending on the supplied value. */ function _swftools_tf($bool) { // String 'false' is treated as TRUE in PHP logic, so force to FALSE if (strtolower($bool) == 'false') { $bool = FALSE; } // Return 'true' or 'false' now we are sure of result return $bool ? 'true' : 'false'; } /** * Identify the most likely SWF Tools action for a file, based on its extension. * * @param $file * The name of the file to be processed. * @return * A string describing an SWF Tools action. */ function swftools_get_action($file) { // Get the path information for this file $path_parts = pathinfo($file); // Select an action based on the file extension switch (strtolower($path_parts['extension'])) { case 'flv': return SWFTOOLS_FLV_DISPLAY; case 'swf': return SWFTOOLS_SWF_DISPLAY_DIRECT; case 'mp3': return SWFTOOLS_MP3_DISPLAY; case 'jpg': case 'gif': case 'png': case 'jpeg': case 'img': return SWFTOOLS_IMAGE_DISPLAY_LIST; default: // Assume that the configured mediaplayer will handle this file or playlist return SWFTOOLS_MEDIA_DISPLAY_LIST; } } /** * Returns the currently configured player for the specified action and profile. * * We use a static array so that if we are generating a complex page we can * quickly locate the relevant action/profile player after we've done it the * first time. This saves us from repeat calls to swftools_variable_get(). * * @param $action * The SWF Tools action to be performed. * @param $profile * The profile being used for this item. * @return * The name of the currently configured player for this action. */ function swftools_get_player($action, $profile = '') { // Initialise a static array for this page call static $players = array(); // We need to give the empty profile a name to place it in the array $_profile = $profile ? $profile : SWFTOOLS_PROFILE_UNDEFINED; // Do we already know the players for this profile? if (!isset($players[$_profile])) { // Register the players for this profile in the array $players[$_profile] = _swftools_get_handlers($profile); } // Return the result return isset($players[$_profile][$action]) ? $players[$_profile][$action] : FALSE; } /** * Return an array of default values to use as the swf parameters. * Parameters are described in the Adobe knowledge base TechNote 12701 * http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701 * * @return * An array of key/value pairs */ function _swftools_params() { // Cache this static $params = array(); // If not set then get defaults if (!$params) { // Define default parameters for case when settings have been stored $defaults = array( 'swliveconnect' => 'false', 'play' => 'true', 'loop' => 'true', 'menu' => 'false', 'allowfullscreen' => 'true', 'quality' => 'autohigh', 'scale' => 'showall', 'align' => 'l', 'salign' => 'tl', 'wmode' => 'opaque', 'bgcolor' => '', 'version' => '7', 'allowscriptaccess' => 'sameDomain', ); // Retrieve settings from the database if available $params = variable_get('swftools_params', $defaults); } // Return the default parameters return $params; } /** * Returns information about the specified file. * * We use this function to try and get the height and width for content that * we don't have a specific size for. * The returned value is an array that may include width, height, extension, * file_size, mime_type. We return FALSE if we didn't get a valid file, or if * image_get_info() couldn't tell us anything. * * @parameter $file * Path to a local file that we want to interrogate. * @return * An array of data, or FALSE if we didn't get anything. */ function swftools_get_info($file) { // Only check the file if it is local // TODO: Is this function capable of checking a path like /drupal6/some/other/file.swf if ($file == file_create_path($file) && $info = image_get_info($file)) { return $info; } // Otherwise return FALSE to indicate that we don't know anything about the file return FALSE; } /** * Generates an xml playlist and places it in {cache_swftools} ready for use. * * We used to create an actual file. Now we place the content in {cache_swftools} * and access it via swftools/playlist/nnn, where nnn is the cid. * * @param &$playlist_data * A formatted array of playlist data that will be converted to an xml file. NEED TO DOCUMENT THE STRUCTURE. * @param $playlist_name * An optional name for the playlist. If not specified a filename will be created. * @param $method * An array describing the selected player method. * @param &$vars * Array of variables. Not used by this function, but will be passed to the playlist generator functions. * @return * The path to the virtual xml file (will be in the form swftools/playlist/nnn) */ function swftools_generate_playlist(&$playlist_data, $playlist_name, &$method, &$vars) { // In what cases would we really want to give a playlist name? // Lets take it out and see if anyone complains! // We don't need to hash again. We have been given a cid via $vars->othervars['cid'] // which is based on the incoming data, so lets just use that. Then we don't have to // hash again. We prefix cache entries with xml: when they are a playlist so the cid // for the playlist will be xml:nnn, and for the movie will be swf:nnn. So we will // end up with matched pairs in the database which is neat. // Assign $vars->othervars['cid'] to a variable so things read nicely! $playlist_name = $vars->othervars['cid']; if ($ret = cache_get('xml:'.$playlist_name, 'cache_swftools')) { return url('swftools/playlist/' . $playlist_name); } // Determine the name of the relevant hook to output the playlist in the appropriate format $hook = $method->player['name'] . '_swftools_playlist'; // Build the name of the function we are going to call $function = $method->player['module'] . '_' . $hook; // Call the function and pass variables by reference $playlist = $function($playlist_data, $method, $vars); // Write data to cache cache_set('xml:'.$playlist_name, $playlist, 'cache_swftools'); // Return the path to the playlist return url('swftools/playlist/' . $playlist_name); } /** * Prepares an array of filenames, or file objects, for use in a playlist. * * This function processes the supplied array and returns an array of playlist data which has * two elements, header and playlist. The header array contains the playlist title, which may * be an empty string if nothing was set. The playlist array contains an array of playlist * elements. As a minimum each element will contain: * - filepath : the filepath for the file, if it is a local file, or FALSE if a full url * - title : the title for the element, set to the filename if nothing given * - filename : the filename for the file * - fileurl : the full url to the file * * drupal_alter is called just prior to returning the playlist, so a module can implement * hook_swftools_playlist_alter(&$playlist_data) to modify the playlist prior to return. This * means other modules can modify, or add, elements. For example, the swftools_getid3 module * implements this hook to attach ID3 data to each playlist element. * * @param $files * An array of files that will be added to the playlist. * @param $title * Optional playlist title * @param $get_action * Optional parameter indicating if the function should determine an appropriate action. Default is TRUE. * @param $type_filter * Optional parameter - an array of file extensions that are permitted * @param $stream * Option parameter to indicate if this is going to be a streamed playlist, in which case checks for the * existence of files should be skipped * @return unknown_type */ function swftools_prepare_playlist_data($files, $title = '', $get_action = TRUE, $type_filter = array(), $stream = FALSE) { /** * Changes coming to this function: * Internally arrays coming in from filefield, text field and link field are * all formatted as an array of arrays. The filter mechanism is being re-written * to do the same. However, not sure if other modules are calling this, so for * now keep the code to map non-arrays. */ // Initialise an array to return the results in $playlist_data = array(); // Set the playlist title $playlist_data['header']['title'] = $title; // Standardise the array of files so subsequent functions are happy _swftools_playlist_standardise_incoming_array($files); // Set the $playlist_data['playlist'] to the uniform array of files $playlist_data['playlist'] = $files; // Iterate over the array of files to ensure all default keys are set to something meaningful foreach ($files AS $key => $data) { // TODO: tidy this up as I'm sure we're repeating in here $playlist_data['playlist'][$key] += array( 'filename' => '', 'filepath' => '', 'fileurl' => '', 'title' => '', ); // If the fileurl element isn't set then build it if (!$data['fileurl']) { // If the filepath element is a valid url then use it if (valid_url($data['filepath'], TRUE)) { // We don't know the filepath, so set to FALSE $playlist_data['playlist'][$key]['filepath'] = FALSE; // We know the url so store it $playlist_data['playlist'][$key]['fileurl'] = $data['filepath']; } // If the fid element is set then we have a file element from the upload module elseif (isset($data['fid'])) { // We have a filename in this instance so store it $playlist_data['playlist'][$key]['filename'] = $data['filename']; // Get the path for the file $source = swftools_src($playlist_data['playlist'][$key]['filepath']); // Build the url from the filepath $playlist_data['playlist'][$key]['fileurl'] = $source['src']; } // Otherwise we're not sure where this element came from else { // Set the filename element to the file filename $playlist_data['playlist'][$key]['filename'] = $data['filename']; // If this playlist isn't a stream // TODO: We will have stream as a parameter on the playlist elements if (!$stream) { // Expand $file as necessary if local or remote $source = swftools_src($data['filepath']); // Store results // TODO: Why are the keys called different things! $playlist_data['playlist'][$key]['filepath'] = $source['src_path']; $playlist_data['playlist'][$key]['fileurl'] = $source['src']; } else { // Set both the filepath and fileurl to the filepath $playlist_data['playlist'][$key]['filepath'] = $data['filepath']; $playlist_data['playlist'][$key]['fileurl'] = $data['filepath']; } } } // Ensure all keys are present on the element $playlist_data['playlist'][$key] = _swftools_playlist_element($playlist_data['playlist'][$key]); // Allow other modules to modify this playlist element drupal_alter('swftools_playlist_element', $playlist_data['playlist'][$key]); // If there is no title for this element create one if (!$playlist_data['playlist'][$key]['title']) { $playlist_data['playlist'][$key]['title'] = $playlist_data['playlist'][$key]['filename']; } } // Call drupal_alter to let other modules modify the playlist if they want drupal_alter('swftools_playlist', $playlist_data); // If a specific action has already been set then return here if (!$get_action) { return $playlist_data; } // Try to work out the action from the files passed $first_valid_file_type = FALSE; $mixed_media = FALSE; // Iterate over the array of playlist elements foreach ($playlist_data['playlist'] AS $key => $data) { // fileurl is always set, irrespective of what we are passing, so use this to determine extension $path_parts = pathinfo($data['fileurl']); // Get the extension for the file $extension = strtolower($path_parts['extension']); // Only try to determine actions if there's an extension to work with if ($extension) { // Determine if this is an image type if (strpos('|jpg|jpeg|gif|png|', $extension)) { // Treat all types of images as the same file type $extension = 'img'; } // Only process the file if $type_filter is empty (ie. no filter) // or if the extension is declared in the $type_filter array. if (!count($type_filter) || in_array($extension, $type_filter)) { // $first_valid_file_type stores the file type of the first valid file. // This will be compared to subsequent files and if two files // have different types, the action will be defined as SWFTOOLS_MEDIA_DISPLAY_LIST // in order to utilize a flexible media player. if (!$first_valid_file_type) { $first_valid_file_type = $extension; } else { if ($first_valid_file_type != $extension) { $mixed_media = TRUE; } } } else { // This file is not desired so remove it unset($playlist_data['playlist'][$key]); } } } // Make a decision based on analysing the file array. if ($first_valid_file_type == '') { // No files passed our test. return FALSE; } // Determine the required action. if ($mixed_media) { // We have files of multiple types. $action = SWFTOOLS_MEDIA_DISPLAY_LIST; } else { // We only had one file type, so discover the action for that type by // calling swftools_get_action() with a dummy filename $action = swftools_get_action('dummy.' . $first_valid_file_type); } // Pluralize the action for multiple files if not already pluralized if (count($playlist_data['playlist']) > 1 && substr($action, -5, 5) != '_list') { $action = $action . '_list'; } // Assign the action to the playlist data ready for return $playlist_data['action'] = $action; // Return the resulting playlist data return $playlist_data; } /** * Implementation of hook_filter_tips(). */ function swftools_filter_tips($delta, $format, $long = false) { if ($long) { return t('

SWF Tools Filter

The basic syntax for embedding a flash file (.swf), flash movie (.flv) or audio file (.mp3) is:

[swf file="filename.swf"]

If you would like to override SWF Tools and flash player default settings, you can specify additional parameters. For example:

[swf file="song.mp3" flashvars="backcolor=#AABBCC&&forecolor=#11AA11"]

If you would like to output a list of files then the format is:

[swf files="image1.jpg&&image2.jpg&&..."]
SWF Tools Filter will accept following:

WARNING: with params, flashvars and othervars, pass multiple values separated by &&.

'); } else { return t('You may use !swftools_filter_help to display Flash files inline', array("!swftools_filter_help" => l('[swf file="song.mp3"]', "filter/tips/$format", array('query' => 'swftools_filter')))); } } /** * Implementation of hook_filter(). */ function swftools_filter($op, $delta = 0, $format = -1, $text = '') { switch ($op) { case 'list': return array(0 => t('SWF Tools filter')); case 'no cache': return FALSE; case 'description': return t('Substitutes [swf file="filename.flv"] or [swf files="file1.jpg&&file2.jpg"] with embedding code.'); case 'prepare': // replace with [swf ] to prevent other filters stripping return (preg_replace('/\<(swflist|swf)\s*(.*)>/sU', '[\1 \2]', $text)); case 'process': return _swftools_filter_process_text($text); } } /** * Processes text obtained from the input filter. * * This function processes the filter text that the user has added to the text area. * If the filter is wrapped in

then these are stripped as part of the processing * This eliminates a validation error in the resulting mark up if SWF Tools filter is * being used in conjunction with other HTML filters that correct line breaks. * It won't work in EVERY case, but it will work in MOST cases. * Filters that are embedded in-line with text will continue to fail validation. */ function _swftools_filter_process_text($text) { $endl = chr(13) ; if (preg_match_all('@(?:

)?\[(swflist|swf)\s*(.*?)\](?:

)?@s', $text, $match)) { // $match[0][#] .... fully matched string // $match[1][#] .... matched tag type ( swf | swflist ) // $match[2][#] .... full params string until the closing '>' $swftools_parameters = array('file', 'params', 'flashvars', 'othervars', 'methods', 'files'); $match_vars = array(); // Initialise an array to hold playlist arrays $files = array(); foreach ($match[2] as $key => $passed_parameters) { //preg_match_all('/(\w*)=\"(.*?)\"/', $passed_parameters, $match_vars[$key]); preg_match_all('/(\w*)=(?:\"|")(.*?)(?:\"|")/', $passed_parameters, $match_vars[$key]); // $match_vars[0][#] .... fully matched string // $match_vars[1][#] .... matched parameter, eg flashvars, params // $match_vars[2][#] .... value after the '=' // Process the parameters onto the $prepared array. // Search for standard parameters, parse the values out onto the array. foreach ($match_vars[$key][1] as $vars_key => $vars_name) { // Switch to swf or swflist, based on file or files // Need to tidy up this line, probably use switch/case if ($vars_name == 'file') { $match[1][$key] = 'swf'; } else { if ($vars_name == 'files') { $match[1][$key] = 'swflist'; } } if ($vars_name == 'file') { $prepared[$key][$vars_name] = $match_vars[$key][2][$vars_key]; unset ($match_vars[$key][1][$vars_key]); } elseif (in_array($vars_name, $swftools_parameters)) { $prepared[$key][$vars_name] = swftools_url_parse(str_replace(array('&&', '&&'), '&', $match_vars[$key][2][$vars_key])); unset ($match_vars[$key][1][$vars_key]); } else { $prepared[$key]['othervars'][$vars_name] = $match_vars[$key][2][$vars_key]; } } // Search for remaining parameters, map them as elements of the standard parameters. if (isset($prepared[$key]['methods']['player'])) { $player = strtolower($prepared[$key]['methods']['player']); } else { $player_key = array_search('player', $match_vars[$key][1]); if ($player_key!==FALSE) { $player = strtolower($match_vars[$key][2][$player_key]); } else { $player = FALSE; } } $prepared[$key]['methods']['player'] = $player; if (count($match_vars[$key][1])) { // Find out if a player has been set. foreach ($match_vars[$key][1] as $vars_key => $vars_name) { if ($parent = swftools_get_filter_alias($vars_name, $player)) { if ($parent) { $prepared[$key][$parent][$vars_name] = $match_vars[$key][2][$vars_key]; } } } } // Just assigning parameters as false if not already set on the $prepared array. // Really just to avoid declaration warnings when we call swf and swf_list if (count($prepared[$key])) { foreach ($swftools_parameters AS $swfparameter) { if (!isset($prepared[$key][$swfparameter])) { $prepared[$key][$swfparameter] = array(); } } } // Assemble in to an array of options ready to pass $options = array(); $options['params'] = $prepared[$key]['params']; $options['flashvars'] = $prepared[$key]['flashvars']; $options['othervars'] = $prepared[$key]['othervars']; $options['methods'] = $prepared[$key]['methods']; // Set a flag to show if we need to determine an action, or if one was provided $get_action = TRUE; if (isset($options['methods']['action'])) { $get_action = FALSE; } switch ($match[1][$key]) { case 'swf': $replace = swf($prepared[$key]['file'], $options); break; case 'swflist': // If this filter contains a key called files if ($prepared[$key]['files']) { // Iterate over the foreach ($prepared[$key]['files'] AS $name => $filename) { if (!$filename) { $prepared[$key]['files'][$name] = $name; } // Put in to proper format for new swftools_prepare_playlist_data() $files[$key][$name]['filepath'] = $prepared[$key]['files'][$name]; } // Work out if this is a streamed playlist (in which case we will skip file existence checks) $stream = FALSE; if (isset($options['othervars']['stream'])) { $stream = TRUE; } // Get playlist data, but don't determine action if the user specified a player $playlist_data = swftools_prepare_playlist_data($files[$key], '', $get_action, array(), $stream); $replace = swf_list($playlist_data, $options); } else { $replace = ''; } break; } $matched[] = $match[0][$key]; $rewrite[] = $replace; } return str_replace($matched, $rewrite, $text); } return $text; } /** * Implements a hook that extends the parameters that can be passed to the filter * so that myvar="value" can be mapped to flashvars, etc. */ function swftools_get_filter_alias($var, $player = FALSE) { static $general_mapping = array(); static $player_mapping = array(); if (!count($general_mapping)) { // Build up the mapping arrays. $general_mapping = array( 'action' => 'methods', 'embed' => 'methods', 'width' => 'params', 'height' => 'params', 'swliveconnect' => 'params', 'play' => 'params', 'loop' => 'params', 'menu' => 'params', 'quality' => 'params', 'scale' => 'params', 'align' => 'params', 'salign' => 'params', 'wmode' => 'params', 'bgcolor' => 'params', 'base' => 'params', 'version' => 'params', 'allowfullscreen' => 'params', 'allowscriptaccess' => 'params', ); if (!count($player_mapping)) { $player_mapping = module_invoke_all('swftools_variable_mapping'); } $combined = array(); if (count($player_mapping)) { foreach($player_mapping AS $mapping) { $combined = array_merge($combined, $mapping); } $general_mapping = array_merge($combined, $general_mapping); } } // Return the parent of the variable. if ($player && isset($player_mapping[$player][$var])) { return $player_mapping[$player][$var]; } else { return (isset($general_mapping[$var])) ? $general_mapping[$var] : FALSE; } } /** * Parses a string passed to the input filter in to separate key value pairs. * * @param $string * The string to parse. * @return * An array of key/value pairs. */ function swftools_url_parse($string) { // TODO: Isn't there a standard function to do this url parsing? $return = array(); $pairs = split("&", $string); foreach($pairs as $pair) { $splitpair = split("=", $pair); //if(!$splitpair[1] || array_key_exists($splitpair[0], $return)) { if(!isset($splitpair[1]) || array_key_exists($splitpair[0], $return)) { $return[] = $splitpair[0]; } else { $return[$splitpair[0]] = $splitpair[1]; } } return $return; } /** * Implementation of hook_theme(). */ function swftools_theme() { return array( 'swftools_embed' => array( 'arguments' => array('embed_code' => NULL, 'action' => NULL, 'methods' => NULL, 'vars' => array(), 'html_alt' => NULL), ), 'swftools_formatter_swftools' => array( 'arguments' => array('element' => NULL, 'profile' => NULL), 'function' => 'theme_swftools_formatter_swftools', ), 'swftools_formatter_swftools_no_file' => array( 'arguments' => array('element' => NULL), 'function' => 'theme_swftools_formatter_swftools', ), 'swftools_formatter_swftools_playlist' => array( 'arguments' => array('element' => NULL, 'profile' => NULL), 'function' => 'theme_swftools_formatter_playlist', ), 'swftools_formatter_swftools_thumbnail' => array( 'arguments' => array('element' => NULL, 'retrieve' => NULL), 'function' => 'theme_swftools_formatter_thumbnail', ), ); } /** * Implementation of hook_file_download(). * * Allows SWF Tools to work with a private file system that might include files * upload outside the control of an upload module, e.g. FTP of large video files. * * If the file is of a supported type, based on extension, then return a valid header. * Note: if any other module returns -1 for this file then access will be denied * even if SWF Tools tries to allow it. See hook_file_download() for details. */ function swftools_file_download($file) { // If SWF Tools is allowed to grant access then check to see if access will be allowed if (variable_get('swftools_grant_access_to_private_files', SWFTOOLS_GRANT_ACCESS_TO_PRIVATE_FILES)) { // Get extension of file in question $extension = pathinfo($file, PATHINFO_EXTENSION); // Get list of extensions that SWF Tools can grant access to $extensions = variable_get('swftools_grant_access_extensions', SWFTOOLS_GRANT_ACCESS_EXTENSIONS); // Need access to the user object global $user; // Check if SWF Tools should grant access - skip the check for user #1 if ($user->uid != 1) { $regex = '/\.('. ereg_replace(' +', '|', preg_quote($extensions)) .')$/i'; if (!preg_match($regex, $file)) { return; } } // Build an array of types that SWF Tools can react to $mime_types = array( 'swf' => 'application/x-shockwave-flash', 'flv' => 'application/octet-stream', 'xml' => 'text/xml', 'mp3' => 'audio/mpeg', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/gif', ); // If file is one of the above types, based on the extension, return headers if ($mime_types[$extension]) { return array( 'Content-Type: '. $mime_types[$extension], 'Content-Length: '. filesize(file_create_path($file)), ); } } } /** * Implementation of hook_swftools_embed(). * * Returns the markup for the page, using compliant HTML. */ function swftools_swftools_embed($action = '', $methods = FALSE, $vars = FALSE, $html_alt = '') { // Create parameters markup $params = '' . "\n"; $params .= '' . "\n"; $params .= '' . "\n"; $params .= '' . "\n"; $params .= '' . "\n"; $params .= '' . "\n"; $params .= '' . "\n"; $params .= '' . "\n"; $params .= '' . "\n"; $params .= '' . "\n"; $params .= '' . "\n"; // Only set background color parameter if it is assigned a value if ($vars->params['bgcolor']) { $params .= '' . "\n"; } // Attach flashvars parameter, if flashvars are present $params .= $vars->flashvars ? '' . "\n" : ''; // Construct embedding markup $html = "\n" . '' . "\n"; $html .= '' . "\n"; $html .= $params; $html .= '' . "\n"; $html .= '' . "\n"; $html .= $params; $html .= '' . "\n"; $html .= $html_alt . "\n"; $html .= '' . "\n"; $html .= '' . "\n"; $html .= '' . "\n"; $html .= '' . "\n"; // Return the result return $html; } /** * Implementation of hook_swftools_methods(). */ function swftools_swftools_methods() { // Initialise array $methods = array(); // Module implements a default plain HTML embedding method called 'direct' $methods[SWFTOOLS_EMBED_METHOD][SWFTOOLS_NOJAVASCRIPT] = array( 'name' => SWFTOOLS_NOJAVASCRIPT, 'module' => 'swftools', 'title' => t('Direct embedding - do not use JavaScript replacement'), ); // Module implements swf embedding $methods[SWFTOOLS_SWF_DISPLAY_DIRECT][SWFTOOLS_SWF] = array( 'name' => SWFTOOLS_SWF, 'module' => 'swftools', 'title' => t('Use SWF file directly, no streaming through another SWF.'), ); // Module implements custom embedding of an swf $methods[SWFTOOLS_SWF_DISPLAY_DIRECT][SWFTOOLS_CUSTOM] = array( 'name' => SWFTOOLS_CUSTOM, 'module' => 'swftools', 'title' => t('Use custom SWF file.'), ); // Add in the methods from swftools_genericplayers.module $methods = array_merge($methods, swftools_genericplayers_swftools_methods()); // Return the methods that are native to SWF Tools return $methods; } /** * Helper function to set the size of the swf content in to $vars->params * * @param $vars * $vars arrays that is being assembled by SWF Tools. * @param $player * The array of player data for the player that will be used. * @return * Nothing - function directly sets $vars. */ function swftools_set_size(&$vars, $player) { // We use these defaults to filter arrays for their height and width, and assign a fallback value $defaults = array('height' => '100%', 'width' => '100%'); // If height and width are already set then just return if (count(array_intersect_key($vars->params, $defaults)) == 2) { return; } // See if we can get height and width from flashvars $try = array_intersect_key($vars->flashvars, $defaults); $vars->params += $try; // See if we can get height and width from player $try = array_intersect_key($player, $defaults); $vars->params += $try; // If we have a height and width now then return if (count(array_intersect_key($vars->params, $defaults)) == 2) { return; } // Try and get size from the file to be embedded, but preserve height or width if just one was set $info = swftools_get_info($vars->othervars['src_path']); // If sizes were retrieved then use them if ($info) { $try = array_intersect_key($info, $defaults); $vars->params += $try; }; // And if all else fails, assign 100% $vars->params += $defaults; } /** * Implementation of hook_field_formatter_info(). */ function swftools_field_formatter_info() { return array( 'swftools_no_file' => array('label' => t('SWF Tools - no download link'), 'field types' => array('filefield', 'link', 'text'), 'multiple values' => CONTENT_HANDLE_CORE, ), 'swftools_playlist' => array('label' => t('SWF Tools - playlist'), 'field types' => array('filefield', 'link', 'text'), 'multiple values' => CONTENT_HANDLE_MODULE, ), 'swftools' => array('label' => t('SWF Tools - with download link'), 'field types' => array('filefield', 'link'), 'multiple values' => CONTENT_HANDLE_CORE, ), 'swftools_thumbnail' => array('label' => t('SWF Tools - thumbnail'), 'field types' => array('filefield', 'link', 'text'), 'multiple values' => CONTENT_HANDLE_CORE, ), ); } /** * Themes a CCK element in to flash content. * * @param $element * The element to render. * @return * A string of markup to produce the flash content, or nothing if the element was empty. */ function theme_swftools_formatter_swftools($element, $profile = array()) { // If the element is empty return if (empty($element['#item']['fid']) && empty($element['#item']['value']) && empty($element['#item']['url'])) { return ''; } // See if a thumbnail image has been stored with this content $image = theme_swftools_formatter_thumbnail('', TRUE, $element['#item']['#delta']); // If an image was stored then set the thumbnail if ($image) { $options['othervars']['image'] = $image; } else { $options = array(); } // Assign the profile $options['othervars']['profile'] = $profile ? $profile['profile'] : ''; // See if we're processing a filefield and get the path and description if (isset($element['#item']['filepath'])) { $swf = $element['#item']['filepath']; $options['othervars']['title'] = $element['#item']['data']['description']; $source = 'filefield'; } // See if we're processing a link field and get the path and title elseif (isset($element['#item']['url'])) { $swf = $element['#item']['url']; $options['othervars']['title'] = $element['#item']['title']; $source = 'link'; // add the query to the base url, if necessary if (isset($element['#item']['query']) && strlen($element['#item']['query']) > 0) { $swf .= '?' . ($element['#item']['query']); } // add the fragment to the url, if necessary if (isset($element['#item']['fragment']) && strlen($element['#item']['fragment']) > 0) { $swf .= '#' . ($element['#item']['fragment']); } } // We're processing a text field so get the path else { $swf = $element['#item']['value']; $options['othervars']['title'] = ''; $source = 'text'; // We need to run $swf through check_url to make sure it is safe, but rtmp isn't in the allowed protocols // This is configurable (see filter.module line 1182) but not sure if the variable is exposed // $swf = check_url($swf); // See if we have been given a stream by trying to explode the string $stream = explode(' ', $swf); // If the explode return 2 elements assume we have a stream, element[0] contains the source, element[1] the file if (count($stream) == 2) { $options['othervars']['stream'] = $stream[0]; $swf = $stream[1]; } } // Pass element to the swf tools processor by attaching it in othervars $options['othervars']['cck'] = $element; // Get the markup for the flash content from swf() $return = swf($swf, $options); // Add the download link if required (we are either using swftools formatter, or a profile with this option enabled) if ($element['#formatter'] == 'swftools' || !empty($profile['download_link'])) { switch ($source) { case 'filefield': $return .= "\n" . theme('filefield_formatter_default', $element); break; case 'link': $return .= "\n" . theme('link_formatter_default', $element); break; } } // Return the resulting markup return $return; } /** * Themes multiple value CCK content in to a playlist. * * @param $element * The element to render. * @return * A string of markup to produce the flash content, or nothing if the element was empty. */ function theme_swftools_formatter_playlist($element, $profile = array()) { // Initialise an array for results $files = array(); // Get the children $children = element_children($element); // If there is only one child then maybe we don't want a playlist if (count($children) == 1) { // Pop the first value of the children array $_children = $children; $child = array_pop($_children); // Get the name of the alternate formatter for this content type $formatter_name = variable_get('swftools_' . $element['#type_name'] . '_' . $element['#field_name'], 'swftools_playlist'); // What happens next depends on the formatter name switch ($formatter_name) { case 'hidden': // If the format is set to hidden then return nothing if ($formatter_name == 'hidden') { return; } case 'swftools_playlist': // If swftools_playlist don't do anything different break; default: // Find out what the alternate formatter should be if ($formatter = _content_get_formatter($formatter_name, 'filefield')) { // We can work out the theme name from the formatter information $theme = $formatter['module'] .'_formatter_'. $formatter_name; // Construct a modified element that mimics a single element $element['#formatter'] = $formatter_name; $element['#theme'] = $theme; $element += $element[$child]; $element['#item']['#delta'] = 0; unset($element[$child]); // Theme this new element according to the alternate formatter return theme($theme, $element); } } } // Retrieve images $images = theme_swftools_formatter_thumbnail('', TRUE); // Cycle through the file elements foreach ($children as $key) { // Is this a filefield? if (isset($element[$key]['#item']['filepath'])) { $files[$key] = array( 'filepath' => $element[$key]['#item']['filepath'], 'title' => $element[$key]['#item']['data']['description'], ); } // Is this a link field? if (isset($element[$key]['#item']['url'])) { $files[$key] = array( 'filepath' => $element[$key]['#item']['url'], 'title' => $element[$key]['#item']['title'], ); } // Is this a text field? // TODO: How to handle streams in a playlist if (isset($element[$key]['#item']['value'])) { $files[$key] = array( 'filepath' => $element[$key]['#item']['value'], 'title' => '', ); } // Is there an image? if (isset($images[$key]) && $images[$key]) { // Get the path to the image $source = swftools_src($images[$key]); // If $source returned a result then use it if ($source) { $files[$key]['image'] = $source['src']; } } } // If files array is empty then there is nothing to be rendered if (empty($files)) { return; } // Initialise an empty options array $options = array(); // Pass element to the swf tools processor by attaching it in othervars $options['othervars']['cck'] = $element; // Assign the profile $options['othervars']['profile'] = $profile ? $profile['profile'] : ''; // But if we got something then we can call swf() now to render it return swf($files, $options); } /** * Theme function to store and retrieve thumbnail images. * * If called as a theme function it stores the path of the image, but if the retrieve flag is set it returns that path. * * In effect this function is a local store to hold the most recently "seen" image on behalf of the swf themer. * In order for this code to work the thumbnail theme function must come before the swf theme function, so it * is necessary to order the fields appropriately on the content configuration page. * * When caching thumbnails then if the element delta is zero the cache is flushed first to start a new * collection of images. * * @param $element * The element to store. * @param $retrieve * When TRUE will return the currently stored path. * @param $delta * If set then attempt to retrieve just the image at the specified delta, otherwise return * the whole array of stored thumbnails. * @return * A string, or an array, holding the thumbnail filepaths. */ function theme_swftools_formatter_thumbnail($element, $retrieve = FALSE, $delta = NULL) { // Create a static variable to hold the image path static $image_path = array(); // It retrieving a previous thumbnail then return its path and reset the stored value // We may want to retrieve all cached thumbnails ($delta = NULL), or a specific thumbnail // in which case $delta is the one we want if ($retrieve) { if ($delta !== NULL) { if (isset($image_path[$delta])) { return $image_path[$delta]; } else { return ''; } } else { return $image_path? $image_path : ''; } } // If the delta is zero we are starting a new collection so reset in case // a retrieval call wasn't made by the theme function if ($element['#item']['#delta'] == 0) { $image_path = array(); } // If the element is empty set the stored path to an empty string if (empty($element['#item']['fid']) && empty($element['#item']['value']) && empty($element['#item']['url'])) { $image_path[] = ''; return; } // Initialise an empty string $image_url = ''; // See if we're processing a filefield and get the appropriate value if (isset($element['#item']['filepath'])) { $image_url = $element['#item']['filepath']; } // See if we're processing a link field and get the appropriate value elseif (isset($element['#item']['url'])) { $image_url = $element['#item']['url']; // add the query to the base url, if necessary if (isset($element['#item']['query']) && strlen($element['#item']['query']) > 0) { $image_url .= '?' . ($element['#item']['query']); } // add the fragment to the url, if necessary if (isset($element['#item']['fragment']) && strlen($element['#item']['fragment']) > 0) { $image_url .= '#' . ($element['#item']['fragment']); } } // We're processing a text field so get the appropriate value else { $image_url = $element['#item']['value']; // Check this is a valid url $image_url = check_url($image_path); } // Store the result $image_path[] = $image_url; // Return nothing at this point return; } /** * Assigns an id on the $options['othervars']['id'] if one wasn't set, and verifies that the id is unique. * * Typically this is called to get us a unique id. We use time() as the basis to ensure we avoid * using the same id twice. If the id is not unique (in the current page creation session) then we * append numbers, using form_clean_id() to do this. * * @param $options * The swftools options array. * @return * An options array with a unique id in the othervars sub-array. */ function swftools_assign_id($options) { // If a specific id wasn't set then assign one using swftools suffixed with time $options['othervars'] += array( 'id' => 'swftools-' . time(), ); // Check the id is unique $options['othervars']['id'] = form_clean_id($options['othervars']['id']); // Return the result return $options; } /** * Returns the default properties for an SWF Tools method. * * @return * Array of keys with default values */ function _swftools_methods() { return array( 'name' => '', 'module' => '', 'file' => '', 'version' => 7, 'title' => '', 'download' => '', 'width' => '', // This used to be 50 - why? 'height' => '', // This used to be 50 - why? 'library' => '', ); } /** * Ensures the default playlist elements are available on the element. * * @param $element * An array (which may be partial) ready to be populated. * @return * An array populated with all default keys. */ function _swftools_playlist_element($element) { /** * Need to decide what the common keys will be... * - filepath: The path to the file (url, or filepath) * - title: Title to use * - description: Description * - author: Author * - image: Thumbnail image * - stream: Streaming server, or empty string if not a stream */ $element += array( 'filepath' => '', 'title' => '', 'description' => '', 'author' => '', 'image' => '', 'stream' => '', ); return $element; } /** * Standardises an array of files so that it is an array of arrays, with a key * named filepath. * * @param $files * Array of files to be processed. * @return * Standardised array. */ function _swftools_playlist_standardise_incoming_array(&$files) { // Iterate over the array of files that were passed foreach ($files AS $key => $data) { // If this $files element is an object convert it to an array if (is_object($data)) { $files[$key] = (array)$data; } // If this $files element isn't an array then build one elseif (!is_array($data)) { // Create an array with key filepath set to the $data string $files[$key] = array( 'filepath' => $data, ); } // Add in standard elements to the array // TODO: Is this step necessary when the overhaul is complete? $files[$key] += array( 'filename' => '', 'filepath' => '', 'fileurl' => '', 'title' => '', ); } } /** * Flushes all caches when new settings are stored. * * This function is called by player modules as part of their settings submit * handlers to ensure all cached content is purged. */ function swftools_admin_settings_submit($form, &$form_state) { // Flush all caches so new players appear drupal_flush_all_caches(); } /** * Creates a relative path url from a file path, using private or public file system. * * This is an SWF Tools version of file_create_url(). The only difference is that * here we do not output absolute paths as we are only using these paths within the * context of a page and therefore relative is fine. * * @param $path * Path to the file. * @return * A string with a complete path, relative to the local file system. */ function swftools_create_url($path) { // Strip file_directory_path from $path. We only include relative paths in urls. if (strpos($path, file_directory_path() .'/') === 0) { $path = trim(substr($path, strlen(file_directory_path())), '\\/'); } // Output a relative url, using public or private file transfer switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) { case FILE_DOWNLOADS_PUBLIC: return base_path() . file_directory_path() . '/' . str_replace('\\', '/', $path); case FILE_DOWNLOADS_PRIVATE: return url('system/files/' . $path); } } /** * Determines the url for a file, and expands its filepath if necessary. * * @param $file * A string containing a url or a path to a file. * @return * An array with two keys * - src: The url to the file (relative if on the local system) * - src_path: The path to the file, expanded if necessary * * This function is necessary because SWF Tools allows flexibility in how the site interprets * filenames. If just a filename is provided then this might point to a file on the local system, * or it might point to an external location if the remote media path is set. However, for things * like auto-detection of sizes to work when the filename is local it must be expanded to include * the file path. * * If $file is a full and valid absolute url then the function returns $file on both keys. * * If $file is full and valid url on the local system then the function returns $file on both keys. * * If $file is a path to a local file (sites/default/files/xxx) then src_path will return this, * and src will return a full relative url. * * If $file is just a filename and remote media is active then src and src_path will both be set * to the url for the external location. * * If $file is just a filename and remote media is not active then src_path will return the path * to the local system (so xxx becomes sites/default/files/xxx) and src will return the full * relative url. */ function swftools_src($file) { // src will contain a full, or relative, url that is used to render the file // src_path will contain a partial path (without webroot), or the original file path $ret = array( 'src' => '', 'src_path' => $file, ); // If already a valid absolute url simply return it if (valid_url($file, TRUE)) { $ret['src'] = $file; return $ret; } // If a valid url, and starts with /, then assume to be a local path relative to web root // No security check is needed as the result of this is only output to the webpage if (valid_url($file) && strpos($file, '/') === 0) { $ret['src'] = $file; return $ret; } // If defintely in the local file system return a relative url to the file if ($file == file_create_path($file)) { // If media checking is active check to see if it actually exists if (variable_get('swftools_check_media', TRUE)) { // If the file doesn't exist, set an error message and return FALSE to indicate failure if (!file_exists($file)) { drupal_set_message(t('SWF Tools could not find %file.', array('%file' => $file)), 'error'); return FALSE; } } // If we got here then return a relative url to the file $ret['src'] = swftools_create_url($file); return $ret; } // Retrieve the media url setting $media_url = trim(variable_get('swftools_media_url', '')); // If a remote path is set build the appropriate url to the file if ($media_url) { $ret['src'] = $media_url . '/' . $path; return $ret; } // If we got here then expand to a local file path and call again return swftools_src(file_create_path($file)); } /** * Returns a string defining a base path for flash to use. */ function swftools_get_base() { // Cache the result as we might get multiple calls static $base = ''; // If $base is not already defined then set it if (!$base) { // Retrieve swftools_media_url to see if a remote path has been set $base = trim(variable_get('swftools_media_url', '')); // If $base is still empty then use local path to file directory if (!$base) { $base = base_path() . file_directory_path() . '/'; } } // Return the base path return $base; } /** * Flatten an array which has sub-arrays in to a single keyed array. * * If keys in the sub-array are the same as ones seen previously the early key will be over-written. * * @param $array * Array to be processed. */ function swftools_flatten_array(&$array) { // Only process if we passed an array if (is_array($array)) { // Iterate over the array foreach($array as $key => $value) { // If the value is in itself an array then flatten that too if (is_array($value)) { // Unset this key as this contains an array unset($array[$key]); // Flatten the sub-array swftools_flatten_array($value); // Merge the flattened sub-array in to the rest of the array $array = array_merge($array, $value); } } } } /** * Returns a variable, or the equivalent variable from the relevant profile. * * This is a custom handler to take care of the SWF Tools profile mechanism. * If no profile name is given then it simply returns the requested variable, * or the default if the variable is not set. * * If a profile name is given then it will first try to retrive the profiled variable. * If that fails it will try to return the global setting, and if that fails then it * will return the default. In this way we cascade through the "most relevant" setting. * * @param $name * The name of the variable to return. * @param $default * The default value to use if this variable has never been set. * @param $profile * The name of the profile to use. * @return * The value of the variable. */ function swftools_variable_get($name, $default, $profile = '') { if ($profile && ($ret = variable_get('swftools_' . $profile . '_' . $name, SWFTOOLS_PROFILE_UNDEFINED)) != SWFTOOLS_PROFILE_UNDEFINED) { return $ret; } return variable_get($name, $default); } /** * Serves an xml playlist from the {cache_swftools} table. * * SWF Tools no longer generates a physical file for the playlist. Instead it * places an entry in its internal cache table and then serves the file from * there. Pages request the files by accessing swftools/playlist/nnn.xml, where * nnn is the cid of the content. * * Note that we check at swf() whether the relevant cid exists in the table. If * it doesn't then the playlist file is regenerated. * * @param $playlist * The name of the playlist being requested. * @return * Serve the xml file, or issue drupal_not_found() if it doesn't exist. */ function swftools_serve_xml_playlist($playlist) { if (!$output = cache_get('xml:'.$playlist, 'cache_swftools')) { print drupal_not_found(); } drupal_set_header('Content-Type: text/xml; charset=utf-8'); print $output->data; } /** * Creates a cid for the call to swf() and returns its data from the cache when available. * * To make our cid we create an array from $file and $options. Then we serialize it, and then * we run it through md5. This generates a unique cid for that piece of content. * * Once the cid is created it is attached to $options['othervars']['cid'] so that * subsequent functions don't have to rehash the data to generate it again. * * Within {cache_swftools} we then prefix the cid with swf: or xml: to indicate whether the * cache entry refers to the markup that produces the content, or the xml: that describes the * playlist. So for xml playlist content we should have two entries with the same numeric portion * in their cid. * * @param $file * The $file parameter from the call to swf(). * @param $options * The $options parameter from the call to swf(). * @return * The cached content, or FALSE if it is isn't available. */ function swftools_fetch_from_cache($file, &$options) { // Construct a cid for this piece of content $cid = md5(serialize(array($file, $options))); // If this is in the cache then return its data if ($ret = cache_get('swf:'.$cid, 'cache_swftools')) { return $ret->data; } // Otherwise set the cid on othervars ready to store this item when we've rendered it $options['othervars']['cid'] = $cid; // Indicate that we don't have cached data return FALSE; } /** * Implementation of hook_flush_caches(). */ function swftools_flush_caches() { return array('cache_swftools'); } /** * Return the default players, or customised players, for each action. */ function _swftools_get_handlers($profile) { $defaults = array( SWFTOOLS_FLV_DISPLAY => SWFTOOLS_GENERIC_FLV, SWFTOOLS_MP3_DISPLAY => SWFTOOLS_GENERIC_MP3, SWFTOOLS_SWF_DISPLAY_DIRECT => SWFTOOLS_SWF, ); // Retrieve settings from the database if available $settings = swftools_variable_get('swftools_handlers', $defaults, $profile); // Return result return $settings; } /** * Merges two multi-dimensional arrays. * * This function is used by players that filter their settings to strip out * blanks or defaults. For the admin page we need a full set of values to prevent * errors. Since the arrays might be multi-dimensional we cannot use a regular * array_merge(). The values in the first array will be over-written by values in * the second, if they exist. * * @param $array1 * The first array to merge. * @param $array2 * The second array to merge. * @return * The result of the merge. */ function swftools_array_merge($array1, $array2) { // Iterate over $array 2 (this is normally the smaller of the two) foreach ($array2 as $key => $value) { // If this key is present in $array1 then work out what to do if (isset($array1[$key])) { // If both keys hold arrays, combine them if (is_array($value) && is_array($array1[$key])) { $array1[$key] = swftools_array_merge($array1[$key], $value); } else { // Replace value in $array1 with that from $array2 $array1[$key] = $value; } } else { // Simply put this value in $array1 if it isn't already in $array1 $array1[$key] = $value; } } // Return the result return $array1; }