t('Video Filter'), 'description' => t('Substitutes [video:URL] with embedded HTML.'), 'process callback' => '_video_filter_process', 'settings callback' => '_video_filter_settings', 'default settings' => array( 'video_filter_width' => '400', 'video_filter_height' => '400', 'video_filter_autoplay' => 1, 'video_filter_related' => 1, 'video_filter_html5' => 1, 'video_filter_codecs' => _video_filter_map_codecs_name(video_filter_get_codec_info()), 'video_filter_multiple_sources' => TRUE, ), 'tips callback' => '_video_filter_tips', // See http://drupal.org/node/1061244. 'weight' => -1, ); return $filters; } function _video_filter_settings($form, &$form_state, $filter, $format, $defaults, $filters) { $settings['video_filter_width'] = array( '#type' => 'textfield', '#title' => t('Default width setting'), '#default_value' => isset($filter->settings['video_filter_width']) ? $filter->settings['video_filter_width'] : $defaults['video_filter_width'], '#maxlength' => 4, ); $settings['video_filter_height'] = array( '#type' => 'textfield', '#title' => t('Default height setting'), '#default_value' => isset($filter->settings['video_filter_height']) ? $filter->settings['video_filter_height'] : $defaults['video_filter_height'], '#maxlength' => 4, ); $settings['video_filter_autoplay'] = array( '#type' => 'radios', '#title' => t('Default autoplay setting'), '#description' => t('Not all video formats support this setting.'), '#default_value' => isset($filter->settings['video_filter_autoplay']) ? $filter->settings['video_filter_autoplay'] : $defaults['video_filter_autoplay'], '#options' => array( 0 => t('No'), 1 => t('Yes'), ), ); $settings['video_filter_related'] = array( '#type' => 'radios', '#title' => t('Related videos setting'), '#description' => t('Show "related videos"? Not all video formats support this setting.'), '#default_value' => isset($filter->settings['video_filter_related']) ? $filter->settings['video_filter_related'] : $defaults['video_filter_related'], '#options' => array( 0 => t('No'), 1 => t('Yes'), ), ); $settings['video_filter_html5'] = array( '#type' => 'radios', '#title' => t('Use HTML5'), '#description' => t('Use HTML5 if the codec provides it. Makes your videos more device agnostic.'), '#default_value' => isset($filter->settings['video_filter_html5']) ? $filter->settings['video_filter_html5'] : $defaults['video_filter_html5'], '#options' => array( 0 => t('No'), 1 => t('Yes'), ), ); $settings['video_filter_multiple_sources'] = array( '#type' => 'radios', '#title' => t('Allow multiple sources'), '#description' => t('Allow the use of multiple sources (used source is selected at random).'), '#default_value' => isset($filter->settings['video_filter_multiple_sources']) ? $filter->settings['video_filter_multiple_sources'] : $defaults['video_filter_multiple_sources'], '#options' => array( 0 => t('No'), 1 => t('Yes'), ), ); $settings['video_filter_codecs'] = array( '#type' => 'checkboxes', '#title' => t('Codecs'), '#description' => t('Choose which codecs will be available.'), '#default_value' => isset($filter->settings['video_filter_codecs']) ? $filter->settings['video_filter_codecs'] : $defaults['video_filter_codecs'], '#options' => _video_filter_map_codecs_name(video_filter_get_codec_info()), ); return $settings; } function _video_filter_map_codecs_name($codecs) { $codecs_map = array(); foreach ($codecs as $codec_cod => $codec) { $codecs_map[$codec_cod] = $codec['name']; } return $codecs_map; } function _video_filter_tips($filter, $format, $long = FALSE) { if ($long) { $codecs = video_filter_get_codec_enabled($filter->settings['video_filter_codecs']); $supported = array(); $instructions = array(); foreach ($codecs as $codec) { $supported[] = $codec['name']; $instructions[] = isset($codec['instructions']) ? '
  • ' . $codec['name'] . ':
    ' . $codec['instructions'] . '
  • ' : ''; } return t('

    Video Filter

    You may insert videos from popular video sites by using a simple tag [video:URL].

    Examples:

    Supported sites: @codecs.

    Special instructions:

    Some codecs need special input. You\'ll find those instructions here. ', array( '@codecs' => implode(', ', $supported), '!instructions' => implode('', $instructions), ) ); } else { return t('You may insert videos with [video:URL]'); } } function _video_filter_process($text, $filter, $format, $langcode, $cache, $cache_id) { if (preg_match_all('/\[video(\:(.+))?( .+)?\]/isU', $text, $matches_code)) { foreach ($matches_code[0] as $ci => $code) { $video = array( 'source' => $matches_code[2][$ci], 'autoplay' => $filter->settings['video_filter_autoplay'], 'related' => $filter->settings['video_filter_related'], ); // Pick random out of multiple sources separated by comma (,). if ($filter->settings['video_filter_multiple_sources'] && strstr($video['source'], ',')) { $sources = explode(',', $video['source']); $random = array_rand($sources, 1); $video['source'] = $sources[$random]; } // Load all codecs. $codecs = video_filter_get_codec_enabled($filter->settings['video_filter_codecs']); // Find codec. foreach ($codecs as $codec_name => $codec) { if (!is_array($codec['regexp'])) { $codec['regexp'] = array($codec['regexp']); } // Try different regular expressions. foreach ($codec['regexp'] as $delta => $regexp) { if (preg_match($regexp, $video['source'], $matches)) { $video['codec'] = $codec; $video['codec']['delta'] = $delta; $video['codec']['matches'] = $matches; // Used in theme function: $video['codec']['codec_name'] = $codec_name; break 2; } } } // Codec found. if (isset($video['codec'])) { // Override default attributes. if ($matches_code[3][$ci] && preg_match_all('/\s+([a-zA-Z_]+)\:(\s+)?([0-9a-zA-Z\/]+)/i', $matches_code[3][$ci], $matches_attributes)) { foreach ($matches_attributes[0] as $ai => $attribute) { $video[$matches_attributes[1][$ai]] = $matches_attributes[3][$ai]; } } // Use configured ratio if present, otherwise use that from the codec, // if set. Fall back to 1. $ratio = 1; if (isset($video['ratio']) && preg_match('/(\d+)\/(\d+)/', $video['ratio'], $tratio)) { // Validate given ratio parameter. $ratio = $tratio[1] / $tratio[2]; } elseif (isset($video['codec']['ratio'])) { if (is_float($video['codec']['ratio']) || is_int($video['codec']['ratio'])) { $ratio = $video['codec']['ratio']; } elseif (preg_match('/(\d+)\s*\/\s*(\d+)/', $video['codec']['ratio'], $cratio)) { $ratio = $cratio[1] / $cratio[2]; } } // Sets video width & height after any user input has been parsed. // First, check if user has set a width. if (isset($video['width']) && !isset($video['height'])) { if ($ratio) { $video['height'] = ceil($video['width'] / $ratio); } else { $video['height'] = $filter->settings['video_filter_height']; } } // Else, if user has set height. elseif (isset($video['height']) && !isset($video['width'])) { if ($ratio) { $video['width'] = ceil($video['height'] * $ratio); } else { $video['width'] = $filter->settings['video_filter_height']; } } // Maybe both? elseif (isset($video['height']) && isset($video['width'])) { $video['width'] = $video['width']; $video['height'] = $video['height']; } // Fall back to defaults. elseif (!isset($video['height']) && !isset($video['width'])) { $video['width'] = $filter->settings['video_filter_width'] != '' ? $filter->settings['video_filter_width'] : 400; $video['height'] = $filter->settings['video_filter_height'] != '' ? $filter->settings['video_filter_height'] : 400; } // Default value for control bar height. $control_bar_height = 0; if (isset($video['control_bar_height'])) { // Respect control_bar_height option if present. $control_bar_height = $video['control_bar_height']; } elseif (isset($video['codec']['control_bar_height'])) { // Respect setting provided by codec otherwise. $control_bar_height = $video['codec']['control_bar_height']; } $video['height'] += $control_bar_height; $video['autoplay'] = (bool) $video['autoplay']; $video['align'] = (isset($video['align']) && in_array($video['align'], array( 'left', 'right', 'center', ))) ? $video['align'] : NULL; // Let modules have final say on video parameters. drupal_alter('video_filter_video', $video); if (isset($video['codec']['html5_callback']) && $filter->settings['video_filter_html5'] == 1 && is_callable($video['codec']['html5_callback'], FALSE)) { $replacement = call_user_func($video['codec']['html5_callback'], $video); } elseif (is_callable($video['codec']['callback'], FALSE)) { $replacement = call_user_func($video['codec']['callback'], $video); } else { // Invalid callback. $replacement = ''; } } // Invalid format. else { $replacement = ''; } $text = str_replace($code, $replacement, $text); } } return $text; } /** * Wrapper that calls the theme function. */ function video_filter_flash($video, $params = array()) { return theme('video_filter_flash', array('video' => $video, 'params' => $params)); } /** * Wrapper that calls the theme function. */ function video_filter_iframe($video) { return theme('video_filter_iframe', array('video' => $video)); } /** * Get a list of all available video codecs. */ function video_filter_get_codec_info() { static $codecs; if (!isset($codecs)) { $codecs = module_invoke_all('codec_info'); drupal_alter('video_filter_codec_info', $codecs); } return $codecs; } /** * */ function _video_filter_merge_format_codecs($filters_codecs) { $codecs = array_pop($filters_codecs); foreach ($filters_codecs as $format_name => $format_codecs) { foreach ($format_codecs as $codec_name => $codec_value) { if (!empty($codec_value) && empty($codecs[$codec_name])) { $codecs[$codec_name] = $codec_value; } } } return $codecs; } /** * Get a list of enabled video codecs. */ function video_filter_get_codec_enabled($video_filter_codecs) { $codecs = array_intersect_key( video_filter_get_codec_info(), array_filter($video_filter_codecs) ); return $codecs; } /** * Function that outputs the element. * * @ingroup themeable */ function theme_video_filter_flash($variables) { $output = ''; $video = $variables['video']; $params = isset($variables['params']) ? $variables['params'] : array(); $classes = video_filter_get_classes($video); $attributes = ''; if (!empty($video['attributes'])) { $attributes = drupal_attributes($video['attributes']); } $output .= '
    ' . "\n"; $defaults = array( 'movie' => $video['source'], 'wmode' => 'transparent', 'allowFullScreen' => 'true', ); $params = array_merge($defaults, (is_array($params) && count($params)) ? $params : array()); foreach ($params as $name => $value) { $output .= ' ' . "\n"; } $output .= '
    ' . "\n"; return $output; } /** * Function that outputs HTML5 compatible iFrame for codecs that support it. * * @ingroup themeable */ function theme_video_filter_iframe($variables) { $video = $variables['video']; $classes = video_filter_get_classes($video); $attributes = ''; if (!empty($video['attributes'])) { $attributes = drupal_attributes($video['attributes']); } $output = '
    '; return $output; } /** * Implements hook_theme(). */ function video_filter_theme($existing, $type, $theme, $path) { return array( 'video_filter_flash' => array( 'variables' => array('video' => NULL, 'params' => NULL), ), 'video_filter_iframe' => array( 'variables' => array('video' => NULL, 'params' => NULL), ), 'video_filter_dashboard' => array( 'variables' => array('form' => NULL), 'template' => 'video_filter_dashboard', ), ); } /** * Helper function that extracts some classes from $video. */ function video_filter_get_classes($video) { $classes = array( 'video-filter', // Add codec name. 'video-' . $video['codec']['codec_name'], ); // Add alignment. if (isset($video['align'])) { $classes[] = 'video-' . $video['align']; } // First match is the URL, we don't want that as a class. unset($video['codec']['matches'][0]); foreach ($video['codec']['matches'] as $match) { $classes[] = 'vf-' . strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $match)); } return $classes; } /** * Implements hook_menu(). */ function video_filter_menu() { $items = array(); $items['video_filter/dashboard/%'] = array( 'title' => 'Videofilter', 'description' => 'Dashboard', 'page callback' => 'video_filter_dashboard_page', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, 'page arguments' => array(2), 'theme callback' => '_video_filter_dashboard_theme', ); $items['video_filter/instructions'] = array( 'title' => 'Videofilter instructions', 'description' => 'instructions', 'page callback' => 'video_filter_instructions_page', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, 'theme callback' => '_video_filter_dashboard_theme', ); return $items; } /** * Return the theme name to be used when showing linkit dashboard */ function _video_filter_dashboard_theme() { return variable_get('admin_theme', 'seven'); } /** * Template preprocess function for video_filter_dashboard(). */ function template_preprocess_video_filter_dashboard(&$variables) { // Construct page title. $variables['head_title'] = t('Video filter dashboard'); $variables['head'] = drupal_get_html_head(); $variables['help'] = theme('help'); $variables['language'] = $GLOBALS['language']; $variables['language']->dir = $GLOBALS['language']->direction ? 'rtl' : 'ltr'; $variables['messages'] = isset($variables['show_messages']) ? theme('status_messages') : ''; $variables['css'] = drupal_add_css(); $variables['styles'] = drupal_get_css(); $variables['scripts'] = drupal_get_js(); } /** * Creates the dashboard. */ function video_filter_dashboard_page($editor) { module_invoke('admin_menu', 'suppress'); // Add CSS. drupal_add_css(drupal_get_path('module', 'video_filter') . '/css/video_filter.css'); switch ($editor) { case 'wysiwyg_tinymce': // Add JavaScript. First, we'll need to determine what version we're on. $has_added_js = FALSE; // Solves bug that causes tinymce.inc to not be loaded. wysiwyg_load_includes('editors', 'editor', 'tinymce'); // Check for TinyMCE 4.x first. if (function_exists('wysiwyg_tinymce_editor')) { $loaded_editor = wysiwyg_tinymce_editor(); $version = wysiwyg_tinymce_version($loaded_editor['tinymce']); if (version_compare($version, '4', '>=')) { drupal_add_js(drupal_get_path('module', 'video_filter') . '/editors/tinymce/video_filter-4.js'); $has_added_js = TRUE; } } // Add JS for <= TinyMCE 3.x. if (!$has_added_js) { drupal_add_js(wysiwyg_get_path('tinymce') . '/jscripts/tiny_mce/tiny_mce_popup.js'); drupal_add_js(drupal_get_path('module', 'video_filter') . '/editors/tinymce/video_filter.js'); } break; case 'ckeditor': case 'wysiwyg_ckeditor': // Add JavaScript. drupal_add_js(drupal_get_path('module', 'video_filter') . '/editors/ckeditor/video_filter_dialog.js'); break; case 'fckeditor': case 'wysiwyg_fckeditor': // Add JavaScript. drupal_add_js(drupal_get_path('module', 'video_filter') . '/editors/fckeditor/video_filter/video_filter_dialog.js'); break; } $form = drupal_get_form('_video_filter_form'); print theme('video_filter_dashboard', array('form' => render($form))); exit(); } /** * Creates the instructions page. */ function video_filter_instructions_page() { module_invoke('admin_menu', 'suppress'); $form = drupal_get_form('_video_filter_instructions_form'); print theme('video_filter_dashboard', array('form' => render($form))); exit(); } function _video_filter_form() { $form['video_filter'] = array( '#type' => 'fieldset', '#title' => t('Insert Video'), '#weight' => 0, '#collapsible' => FALSE, '#collapsed' => FALSE, '#attributes' => array('class' => array('clearfix')), ); $form['video_filter']['file_url'] = array( '#type' => 'textfield', '#title' => t('Video URL'), '#maxlength' => 255, '#size' => 80, '#default_value' => '', '#weight' => 1, ); $form['video_filter']['width'] = array( '#type' => 'textfield', '#title' => t('Width'), '#maxlength' => 255, '#size' => 80, '#default_value' => '', '#weight' => 2, ); $form['video_filter']['height'] = array( '#type' => 'textfield', '#title' => t('Height'), '#maxlength' => 255, '#size' => 80, '#default_value' => '', '#weight' => 3, ); $form['video_filter']['align'] = array( '#type' => 'select', '#title' => t('Align'), '#default_value' => 'none', '#options' => array( 'none' => t('None'), 'left' => t('Left'), 'right' => t('Right'), 'center' => t('Center'), ), '#weight' => 4, ); $form['video_filter']['autoplay'] = array( '#type' => 'checkbox', '#title' => t('Autoplay'), '#weight' => 5, ); $form += _video_filter_instructions_form(); $form['cancel'] = array( '#type' => 'button', '#value' => t('Cancel'), '#weight' => 98, ); $form['insert'] = array( '#type' => 'button', '#value' => t('Insert'), '#weight' => 99, ); return $form; } function _video_filter_instructions_form() { $form['instructions'] = array( '#type' => 'fieldset', '#title' => t('Instructions'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#attributes' => array('class' => array('clearfix')), '#weight' => 97, ); $text = '

    ' . t('Insert a 3rd party video from one of the following providers; this list may vary depending on the text format being used.') . '

    '; $text .= _video_filter_instructions(); $form['instructions']['text'] = array( '#type' => 'item', '#markup' => $text, ); return $form; } /** * Implements hook_ckeditor_plugin(). */ function video_filter_ckeditor_plugin() { $plugins = array(); $plugins['video_filter'] = array( 'name' => 'video_filter', 'desc' => t('Plugin to directly embed videos with the video filter module.'), 'path' => drupal_get_path('module', 'video_filter') . '/editors/ckeditor/', 'buttons' => array( 'video_filter' => array( 'label' => t('Video filter'), 'icon' => 'video_filter.png', ), ), ); return $plugins; } function video_filter_wysiwyg_plugin($editor, $version) { _video_filter_add_settings('wysiwyg_' . $editor); $plugins = array(); switch ($editor) { case 'ckeditor': $plugins['video_filter'] = array( 'path' => drupal_get_path('module', 'video_filter') . '/editors/ckeditor/', 'buttons' => array('video_filter' => t('Video filter')), 'url' => 'http://drupal.org/project/video_filter', 'load' => TRUE, ); break; case 'fckeditor': $plugins['video_filter'] = array( 'path' => drupal_get_path('module', 'video_filter') . '/editors/fckeditor/', 'buttons' => array('video_filter' => t('Video filter')), 'url' => 'http://drupal.org/project/video_filter', 'load' => TRUE, ); break; case 'tinymce': $plugins['video_filter'] = array( 'path' => drupal_get_path('module', 'video_filter') . '/editors/tinymce', 'filename' => 'editor_plugin.js', 'buttons' => array('video_filter' => t('Video filter')), 'url' => 'http://drupal.org/project/video_filter', 'load' => TRUE, ); break; } return $plugins; } /** * Implements hook_element_info_alter(). */ function video_filter_element_info_alter(&$types) { if (isset($types['text_format']['#pre_render']) && is_array($types['text_format']['#pre_render'])) { if (in_array('ckeditor_pre_render_text_format', $types['text_format']['#pre_render'])) { _video_filter_add_settings('ckeditor'); } } } function _video_filter_add_settings($editor) { static $editor_settings_added = array(); static $global_settings_added = FALSE; if (!isset($editor_settings_added[$editor])) { $editor_settings_added[$editor] = TRUE; // Add popup url. $settings = array( 'video_filter' => array( 'url' => array($editor => url('video_filter/dashboard/' . $editor)), 'instructions_url' => url('video_filter/instructions'), ), ); drupal_add_js($settings, 'setting'); } if (!$global_settings_added) { $global_settings_added = TRUE; // Add global settings for video_filter. $settings = array( 'video_filter' => array( 'modulepath' => drupal_get_path('module', 'video_filter'), ), ); drupal_add_js($settings, 'setting'); } } /** * Parses Codec into instructions for WYSIWYG popup. */ function _video_filter_instructions() { // Get all codecs the user has permission to use in at least one text format. global $user; $formats = filter_formats($user); $filters_codecs = array(); foreach ($formats as $format) { $format_filters = filter_list_format($format->format); if (isset($format_filters['video_filter'])) { $filters_codecs[$format->name] = $format_filters['video_filter']->settings['video_filter_codecs']; } } $video_filter_codecs = _video_filter_merge_format_codecs($filters_codecs); $codecs = video_filter_get_codec_enabled($video_filter_codecs); $output = ''; return $output; } /** * Requests data from an oEmbed provider. * * Note: This function currently only supports JSON responses. * * @param string $endpoint * The provider endpoint URL. * @param array $arguments * An associative array of URL arguments to send the provider. * * @return array|FALSE * An array of data if the request is successful, otherwise FALSE. * * @todo Support other response formats than JSON? */ function video_filter_oembed_request($endpoint, array $arguments) { // Make HTTP request. $result = drupal_http_request(url($endpoint, array('query' => $arguments))); if ($data = json_decode($result->data)) { // Success. return (array) $data; } else { // Failure. Either the resource doesn't exist or there was an error with the // request. return FALSE; } }