You are here

jw_player.module in JW Player 7

Same filename and directory in other branches
  1. 8 jw_player.module
  2. 7.2 jw_player.module

Adds a theme function which allows theme developers to use the JW Player.

File

jw_player.module
View source
<?php

/**
 * @file
 * Adds a theme function which allows theme developers to use the JW Player.
 */

/**
 * Implements hook_menu().
 */
function jw_player_menu() {
  $items['admin/config/media/jw_player/settings'] = array(
    'title' => 'Settings',
    'description' => 'JW Player general settings',
    'type' => MENU_LOCAL_TASK,
    'access arguments' => array(
      'administer JW Player presets',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'jw_player_settings_form',
    ),
    'file' => 'jw_player.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function jw_player_permission() {
  return array(
    'administer JW Player presets' => array(
      'title' => t('administer JW Player presets'),
      'description' => t('Perform administration of JW Player presets'),
    ),
  );
}

/**
 * Implements hook_theme().
 */
function jw_player_theme() {
  return array(
    'jw_player' => array(
      'variables' => array(
        'file_object' => NULL,
        'sources' => '',
        'preset' => '',
        'image' => '',
        'html_id' => NULL,
        'options' => array(),
      ),
      'template' => 'theme/jw_player',
    ),
  );
}

/**
 * Implements hook_field_formatter_info().
 */
function jw_player_field_formatter_info() {
  $formatters = array(
    'jw_player' => array(
      'label' => t('JW player'),
      'field types' => array(
        'file',
      ),
      'settings' => array(
        'jwplayer_preset' => '',
      ),
    ),
  );
  return $formatters;
}

/**
 * Implements hook_field_formatter_settings_form().
 */
function jw_player_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  $element = array();
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];

  // Formatter types.
  switch ($display['type']) {
    case 'jw_player':
      $presets = jw_player_preset_load();

      // If there are presets prompt the user to select one or create another.
      // If no, prompt to create a preset.
      if (!empty($presets)) {
        foreach (jw_player_preset_load() as $preset => $item) {
          $options[$preset] = $item['preset_name'];
        }
        $element['jwplayer_preset'] = array(
          '#title' => t('Select preset'),
          '#type' => 'select',
          '#default_value' => $settings['jwplayer_preset'] ? $settings['jwplayer_preset'] : FALSE,
          '#options' => $options,
        );
        $element['links'] = array(
          '#theme' => 'links',
          '#links' => array(
            array(
              'title' => t('Create new preset'),
              'href' => 'admin/config/media/jw_player/add',
            ),
            array(
              'title' => t('Manage presets'),
              'href' => 'admin/config/media/jw_player',
            ),
          ),
        );
      }
      else {
        $element['no_preset_message'] = array(
          '#markup' => '<div class="messages warning">' . t('No presets are available. You must to <a href="@create">create a preset</a> to proceed.', array(
            '@create' => url('admin/config/media/jw_player/add'),
          )) . '</div>',
        );
      }
      break;
    default:
      break;
  }
  return $element;
}

/**
 * Implements hook_field_formatter_settings_summary().
 */
function jw_player_field_formatter_settings_summary($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $summary = array();
  $presets = jw_player_preset_load();
  if (isset($presets[$settings['jwplayer_preset']])) {
    $summary[] = t('Preset: @name', array(
      '@name' => $presets[$settings['jwplayer_preset']]['preset_name'],
    ));
    $summary[] = t('Description: @description', array(
      '@description' => $presets[$settings['jwplayer_preset']]['description'],
    ));
    $settings = $presets[$settings['jwplayer_preset']]['settings'];
    foreach ($settings as $key => $val) {

      // Filter out complex settings in the form of arrays (such as plugins).
      // @todo Tackle the display of enabled plugins separately.
      if (!is_array($val)) {
        $summary[] = t('@key: @val', array(
          '@key' => $key,
          '@val' => !empty($val) ? $val : t('default'),
        ));
      }
    }
  }
  else {
    $summary[] = t('No preset selected');
  }
  return implode('<br />', $summary);
}

/**
 * Implements hook_field_formatter_view().
 */
function jw_player_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  if ($display['type'] == 'jw_player') {

    // Process files for the theme function.
    $files = array();
    foreach ($items as $delta => $item) {
      $files[$delta] = (object) $item;
    }
    foreach ($files as $delta => $file) {

      // Give each instance of the player a unique id. The combination
      // of fid and preset are considered to be save even in cases where
      // the entire theme functions output is cached.
      // Prefixing the id makes sure that the id does not start with a
      // invalid numeric value.
      $id = $file->fid . $display['settings']['jwplayer_preset'];
      $element[$delta] = array(
        '#theme' => 'jw_player',
        '#file_object' => $file,
        '#preset' => $display['settings']['jwplayer_preset'],
        '#html_id' => drupal_html_id('jwplayer' . $id),
      );
    }
  }
  return $element;
}

/**
 * Retrieves all available skins.
 */
function jw_player_skins($name = NULL) {
  $skins =& drupal_static(__FUNCTION__);
  if (!isset($skins)) {
    $directory = libraries_get_path('jwplayer_skins');
    $skins = file_scan_directory($directory, '/\\.xml|\\.swf$/');
  }
  if ($name) {
    foreach ($skins as $file) {
      if ($file->name == $name) {
        return $file;
      }
    }
  }
  return $skins;
}

/**
 * Implements hook_ctools_plugin_api().
 */
function jw_player_ctools_plugin_api($owner, $api) {
  if ($owner == 'jw_player' && $api == 'jw_player_presets') {
    return array(
      'version' => 1,
    );
  }
}

/**
 * Implements hook_ctools_plugin_directory().
 */
function jw_player_ctools_plugin_directory($module, $type) {

  // Load the export_ui plugin.
  if ($type == 'export_ui') {
    return 'plugins/export_ui';
  }
}

/**
 * Load the given preset(s).
 * @param string $machine_name
 * @return array
 */
function jw_player_preset_load($machine_name = NULL) {
  ctools_include('export');
  if (isset($machine_name)) {
    $items = ctools_export_crud_load('jwplayer_preset', $machine_name);

    // CTools returns an object, so we explictly typecast it to array before
    // returning.
    return $items = (array) $items;
  }
  else {
    $result = ctools_export_crud_load_all('jwplayer_preset');
    if (!empty($result)) {
      foreach ($result as $key => $item) {
        $items[$key] = (array) $item;
      }
      return $items;
    }
  }
}

/**
 * Returns the default settings for JW Player. Used in cases where a preset is
 * not provided when the JW Player theme function is called.
 */
function jw_player_default_settings() {
  $defaults =& drupal_static(__FUNCTION__);
  if (!isset($defaults)) {
    $defaults = array(
      'flashplayer' => file_create_url(libraries_get_path('jwplayer') . '/player.swf'),
      'width' => '640',
      'height' => '480',
      'autoplay' => FALSE,
      'controlbar' => 'bottom',
    );
  }
  return $defaults;
}

/**
 * Process variables for jw_player.tpl.php.
 *
 * @param $variables
 *   An array that must contain one (and only one) of the following:
 *   - $file_object The file object you would like JW Player to play.
 *   - $sources If you would like to play a URL directly instead of a file
 *     object the URL can be passed directly to the theme function. The file URL
 *     must be provided within an array. This is helpful for playing back the
 *     contents of link fields. Optionally the array can contain multiple URLS
 *     to allow for multiple video formats or adaptive bitrate switching. Here
 *     is a sample sources array that contains two formats of a video:
 *
 *     @code
 *     $variables['sources'] = array(
 *       array(
 *         'file_path' => 'http://example.com/video.ogg',
 *         'file_mime' => 'video/ogg',
 *       ),
 *       array(
 *         'file_path' => 'http://example.com/video.m4v',
 *         'file_mime' => 'video/mp4',
 *       ),
 *     );
 *     @endcode
 *
 *     To use adaptive bitrate switching two additional parameters - with and
 *     and bitrate are to be provided. *Note that adaptive bitrate is only
 *     supported in the flash version of the player. In preprocessing the player
 *     will automatically switch to flash playback mode when two sources are
 *     supplied with bitrates.
 *
 *   The following optional variables can also be set:
 *   - $preset (highly recommended!) The machine name of the JW Player preset
 *     you would like to use. Template preprocessing will take care of applying
 *     the preset's settings for you.
 *   - $image URL for the image ("poster" in HTML 5 video) to use as the video
 *     preview.
 *   - $options Additional options for the player. These options will override
 *     The module's defaults as well as the presets defaults.
 *
 * @see jw_player.tpl.php
 */
function template_preprocess_jw_player(&$variables) {

  // If a file object has been passed populate the sources array with the
  // variables derived from it.
  if (isset($variables['file_object'])) {
    $variables['sources'] = array(
      array(
        'file_path' => file_create_url($variables['file_object']->uri),
        'file_mime' => $variables['file_object']->filemime,
      ),
    );
  }

  // Load defaults as the starting point.
  $default_settings = jw_player_default_settings();

  // Load preset if set.
  $preset_settings = array();
  if (!empty($variables['preset'])) {
    $preset = jw_player_preset_load($variables['preset']);

    // Additional check to ensure that the preset has actually loaded. This
    // prevents problems where a preset has been deleted but a field is still
    // configured to use it.
    if (!empty($preset)) {
      $preset_settings = $preset['settings'];
    }
  }

  // Get any preset override options that were sent through the formatter or
  // theme call.
  $options = array();
  if (isset($variables['options'])) {
    $options = $variables['options'];
    unset($variables['options']);
  }

  // Merge all variables together. Preset settings take priority over defaults,
  // variables passed directly to the theme function take priority over both.
  $variables = array_merge($default_settings, $preset_settings, $options, $variables);

  // The html_id should have been previously set. But we need to make
  // sure we do have one.
  if (!isset($variables['html_id'])) {
    $id = $variables['file_object']->fid . $variables['preset'];
    $variables['html_id'] = drupal_html_id('jwplayer' . $id);
  }

  // Check if there is one or multiple files. If one file then we set 'file', if
  // there are multiple files we set 'levels'. Note that levels is used for both
  // multiple video formats as well as for adaptive bitrates.
  if (count($variables['sources']) > 1) {
    $variables['config']['levels'] = array();
    foreach ($variables['sources'] as $key => $source) {
      $variables['config']['levels'][$key]['file'] = $source['file_path'];
      if (isset($source['bitrate'])) {
        $variables['config']['levels'][$key]['bitrate'] = $source['bitrate'];
      }
      if (isset($source['width'])) {
        $variables['config']['levels'][$key]['width'] = $source['width'];
      }
    }
  }
  else {
    $variables['config']['file'] = $variables['sources'][0]['file_path'];
  }

  // Resolve skin url
  $skin = !empty($variables['skin']) ? jw_player_skins($variables['skin']) : '';
  $variables['skin'] = !empty($skin) ? file_create_url($skin->uri) : '';

  // Copy player variables into their own array to be set as JavaScript
  // configuration.
  // @todo Bad smell here. Refactoring needed.
  $config_variables = array(
    'width',
    'height',
    'image',
    'controlbar',
    'playlist.position',
    'playlist.size',
    'skin',
    'autoplay',
  );
  foreach ($config_variables as $key) {
    if (!empty($variables[$key])) {
      $variables['config'][$key] = $variables[$key];
    }
  }

  // Initalize the player modes. The order of this array determines which
  // playback mode will be tried first before the browser falls back to the next
  // option. The default is html5 first, but this can be overridden by a preset
  // (see the code directly below).
  $variables['config']['modes'] = array(
    array(
      'type' => 'html5',
    ),
    array(
      'type' => 'flash',
      'src' => file_create_url(libraries_get_path('jwplayer') . '/player.swf'),
    ),
  );

  // If the preset has the primary mode set, modify the modes array so that it
  // comes first.
  if (isset($variables['mode'])) {
    foreach ($variables['config']['modes'] as $key => $value) {
      if ($value['type'] == $variables['mode']) {
        unset($variables['config']['modes'][$key]);
        array_unshift($variables['config']['modes'], $value);
      }
    }
  }

  // Copy over all enabled plugins into the 'config' section as this is the key
  // that is sent over to the player.
  if (!empty($variables['plugins'])) {
    foreach ($variables['plugins'] as $plugin => $info) {
      if (!$info['enable']) {
        continue;
      }
      $variables['config']['plugins'][$plugin] = $info;
    }
  }
}

/**
 * Implements hook_process_HOOK().
 *
 * Add the JW Player Javascript according to the method selected.
 */
function jw_player_process_jw_player(&$variables) {

  // If inline option is selected, add the js code inline. It will be printed
  // in the tpl file. This is needed so that the videos still have their config
  // after page is cached. In this case the player itself is loaded on all pages
  // via hook_init().
  if (variable_get('jw_player_inline_js', TRUE)) {
    $variables['jw_player_inline_js_code'] = stripslashes(json_encode($variables['config']));
  }
  else {

    // Add library.
    drupal_add_js(libraries_get_path('jwplayer') . '/jwplayer.js');

    // Attaches JW Player element.
    drupal_add_js(drupal_get_path('module', 'jw_player') . '/jw_player.js');
    drupal_add_js(array(
      'jw_player' => array(
        $variables['html_id'] => $variables['config'],
      ),
    ), 'setting');

    // Player settings
    // Add key if available.
    // @todo: Is added multiple times if there are multiple players on one page.
    if ($key = variable_get('jw_player_key', NULL)) {
      drupal_add_js('jwplayer.key="' . $key . '"', array(
        'type' => 'inline',
        'scope' => 'header',
        'weight' => 5,
      ));
    }
  }

  // Add js file that enables url based seeking.
  drupal_add_js(drupal_get_path('module', 'jw_player') . '/jw_player_seek.js');
}

/**
 * Implements hook_init().
 *
 * If the player configuration is set to print inline, load the JW Player
 * JavaScript on all pages. Due to caching one never knows when it will be
 * needed.
 */
function jw_player_init() {
  if (variable_get('jw_player_inline_js', FALSE)) {

    // Add library
    drupal_add_js(libraries_get_path('jwplayer') . '/jwplayer.js');

    // Add key if available.
    if ($key = variable_get('jw_player_key', NULL)) {
      drupal_add_js('jwplayer.key="' . $key . '"', array(
        'type' => 'inline',
        'scope' => 'header',
        'weight' => 5,
      ));
    }
  }
}

/**
 * Retrieves all available preset plugins.
 */
function jw_player_preset_plugins($name = NULL) {
  $plugins =& drupal_static(__FUNCTION__);
  if (!isset($plugins)) {
    $plugins = module_invoke_all('jw_player_plugin_info');

    // Allow modules to alter other modules' plugin definitions
    drupal_alter('jw_player_plugin_info', $plugins);
  }
  if ($name && isset($plugins[$name])) {
    return $plugins[$name];
  }
  return $plugins;
}

Functions

Namesort descending Description
jw_player_ctools_plugin_api Implements hook_ctools_plugin_api().
jw_player_ctools_plugin_directory Implements hook_ctools_plugin_directory().
jw_player_default_settings Returns the default settings for JW Player. Used in cases where a preset is not provided when the JW Player theme function is called.
jw_player_field_formatter_info Implements hook_field_formatter_info().
jw_player_field_formatter_settings_form Implements hook_field_formatter_settings_form().
jw_player_field_formatter_settings_summary Implements hook_field_formatter_settings_summary().
jw_player_field_formatter_view Implements hook_field_formatter_view().
jw_player_init Implements hook_init().
jw_player_menu Implements hook_menu().
jw_player_permission Implements hook_permission().
jw_player_preset_load Load the given preset(s).
jw_player_preset_plugins Retrieves all available preset plugins.
jw_player_process_jw_player Implements hook_process_HOOK().
jw_player_skins Retrieves all available skins.
jw_player_theme Implements hook_theme().
template_preprocess_jw_player Process variables for jw_player.tpl.php.