videojs.module in Video.js (HTML5 Video Player) 7.3
Same filename and directory in other branches
Provides an HTML5-compatible with Flash-fallback video player.
This module provides functionality for loading the Video.js library and formatters for CCK FileFields.
File
videojs.moduleView source
<?php
/**
* @file
* Provides an HTML5-compatible with Flash-fallback video player.
*
* This module provides functionality for loading the Video.js library and
* formatters for CCK FileFields.
*/
// Solve all issues with updating from 7.x-2.x to 7.x-3.x.
require_once __DIR__ . '/includes/videojs.utility.inc';
/**
* Implements hook_menu().
*/
function videojs_menu() {
$items = array();
$items['admin/config/media/videojs'] = array(
'title' => 'Video.js',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'videojs_settings_form',
),
'access arguments' => array(
'administer site configuration',
),
'description' => 'Configure the settings for the Video.js module.',
'file' => 'includes/videojs.admin.inc',
);
return $items;
}
/**
* Implements hook_theme().
*/
function videojs_theme() {
return array(
'videojs' => array(
'variables' => array(
'items' => NULL,
'player_id' => NULL,
'attributes' => NULL,
'entity' => NULL,
'entity_type' => NULL,
'posterimage_style' => NULL,
),
'template' => 'theme/videojs',
'file' => 'includes/videojs.theme.inc',
),
// Special theme function for use in wysiwyg editors via the media module.
'videojs_media_wysiwyg_preview' => array(
'variables' => array(
'items' => NULL,
'player_id' => NULL,
'attributes' => NULL,
'entity' => NULL,
'entity_type' => NULL,
'posterimage_style' => NULL,
),
'template' => 'theme/videojs-media-wysiwyg-preview',
'file' => 'includes/videojs.theme.inc',
),
);
}
/**
* Implements hook_field_formatter_info().
*/
function videojs_field_formatter_info() {
module_load_include('inc', 'videojs', 'includes/videojs.utility');
$options = videojs_utility::getDefaultDisplaySettings();
foreach (array_keys($options) as $key) {
$options[$key] = NULL;
}
$options['posterimage_field'] = NULL;
$options['posterimage_style'] = NULL;
$options['tracks_field'] = NULL;
return array(
'videojs' => array(
'label' => t('Video.js'),
'field types' => array(
'file',
'media',
'link_field',
),
'description' => t('Display a video file as an HTML5-compatible player with Flash-fallback.'),
'settings' => $options,
),
);
}
/**
* Implements hook_field_formatter_view().
*/
function videojs_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
if ($display['type'] !== 'videojs') {
return array();
}
if (empty($items)) {
return array();
}
videojs_utility::normalizeFieldItems($field['field_name'], $items, 'video/mp4');
$settings = $display['settings'];
$attributes = array();
if (!empty($settings['width']) && !empty($settings['height'])) {
$attributes['width'] = intval($settings['width']);
$attributes['height'] = intval($settings['height']);
}
if ($settings['autoplay'] !== NULL) {
$attributes['autoplay'] = $settings['autoplay'];
}
if ($settings['loop'] !== NULL) {
$attributes['loop'] = $settings['loop'];
}
if ($settings['hidecontrols'] !== NULL) {
$attributes['hidecontrols'] = $settings['hidecontrols'];
}
if ($settings['preload'] !== NULL) {
$attributes['preload'] = $settings['preload'];
}
if ($settings['centeredplaybutton'] !== NULL) {
$attributes['centeredplaybutton'] = $settings['centeredplaybutton'];
}
// Add the poster image.
if (!empty($settings['posterimage_field']) && !empty($entity->{$settings['posterimage_field']})) {
$images = field_get_items($entity_type, $entity, $settings['posterimage_field']);
if (!empty($images)) {
videojs_utility::normalizeFieldItems($settings['posterimage_field'], $images, 'image/jpeg', 'image/');
array_unshift($items, array_shift($images));
}
}
// Add the text tracks.
if (!empty($settings['tracks_field'])) {
$tracks = field_get_items($entity_type, $entity, $settings['tracks_field']);
if (!empty($tracks)) {
videojs_utility::normalizeFieldItems($settings['tracks_field'], $tracks, 'text/vtt', 'text/vtt');
$items = array_merge($items, $tracks);
}
}
// Post-process tracks.
$hastracks = FALSE;
foreach ($items as &$item) {
if ($item['filemime'] != 'text/vtt') {
continue;
}
// Try to find the language for subtitles by reading the description field.
if (empty($item['langcode']) && !empty($item['description'])) {
$language = videojs_utility::resolveLanguage($item['description']);
if ($language !== NULL) {
$item['langcode'] = $language[0];
if (empty($item['label'])) {
$item['label'] = $language[1];
}
}
}
$hastracks = TRUE;
}
// Select the default track.
if ($hastracks && !empty($settings['defaulttrack'])) {
foreach ($items as &$item) {
if ($item['filemime'] != 'text/vtt') {
continue;
}
switch ($settings['defaulttrack']) {
case 'first':
$item['default'] = TRUE;
break 2;
case 'user':
global $language;
if ($item['langcode'] == $language->language) {
$item['default'] = TRUE;
break 2;
}
break;
default:
if ($item['langcode'] == $settings['defaulttrack']) {
$item['default'] = TRUE;
break 2;
}
break;
}
}
}
$themefunction = 'videojs';
// Special handling for file entity based videos that can be added using the media module.
if ($entity_type == 'file' && !empty($entity->override)) {
if (!empty($entity->override['wysiwyg'])) {
// When in wysiwyg mode, use a special theme function because
// media only handles images or spans in the wysiwyg area.
$themefunction = 'videojs_media_wysiwyg_preview';
}
elseif (!empty($entity->override['attributes'])) {
// Allow the user to override width and height by resizing the player
// in the wysiwyg area.
if (!empty($entity->override['attributes']['width'])) {
$attributes['width'] = intval($entity->override['attributes']['width']);
}
if (!empty($entity->override['attributes']['height'])) {
$attributes['height'] = intval($entity->override['attributes']['height']);
}
if (!empty($entity->override['attributes']['class'])) {
$attributes['class'] = $entity->override['attributes']['class'];
}
else {
$attributes['class'] = array();
}
$attributes['class'][] = 'videojs-' . $entity->fid;
$attributes['class'][] = 'videojs-' . $entity->type;
}
}
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
return array(
array(
'#theme' => $themefunction,
'#items' => $items,
'#player_id' => 'videojs-' . $id . '-' . str_replace('_', '-', $instance['field_name']),
'#attached' => videojs_add(FALSE),
'#entity' => $entity,
'#entity_type' => $entity_type,
'#attributes' => $attributes,
'#posterimage_style' => !empty($settings['posterimage_style']) ? $settings['posterimage_style'] : NULL,
),
);
}
/**
* Implements hook_field_formatter_settings_form().
*/
function videojs_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$entity_type = NULL;
$bundle = NULL;
if (isset($instance['entity_type']) && isset($instance['bundle'])) {
$entity_type = $instance['entity_type'];
$bundle = $instance['bundle'];
}
elseif (isset($form['#file_type'])) {
// The file entity module does not supply the entity type and bundle like
// Drupal core does.
// @todo: file a feature request.
$entity_type = 'file';
$bundle = $form['#file_type'];
}
if ($entity_type != NULL && $bundle != NULL) {
$imagefields = videojs_utility::findFieldsByType($field, $entity_type, $bundle, array(
'image',
'imagefield_crop',
'link',
'file',
));
unset($imagefields[$field['field_name']]);
$trackfields = videojs_utility::findFieldsByType($field, $entity_type, $bundle, array(
'link',
'file',
));
unset($trackfields[$field['field_name']]);
}
$form = array(
'#element_validate' => array(
'videojs_field_formatter_settings_form_validate',
),
);
videojs_utility::getDisplaySettingsForm($form, $settings);
if (!empty($imagefields)) {
$form['posterimage_field'] = array(
'#type' => 'select',
'#title' => t('Poster image field'),
'#default_value' => $settings['posterimage_field'],
'#options' => $imagefields,
'#description' => t('If an image is uploaded to the field above it will be used as the poster image.'),
'#empty_value' => '',
);
if (module_exists('image')) {
$image_styles = image_style_options(FALSE);
$form['posterimage_style'] = array(
'#type' => 'select',
'#title' => t('Poster image style'),
'#default_value' => $settings['posterimage_style'],
'#empty_option' => t('None (original image)'),
'#description' => t('The original video thumbnail will be displayed. Otherwise, you can add a custom image style at !settings.', [
'!settings' => l(t('media image styles'), 'admin/config/media/image-styles'),
]),
'#options' => $image_styles,
);
}
if ($field['type'] == 'file') {
$form['posterimage_field']['#description'] .= ' ' . t('Images uploaded to this field will be used as poster image by default.');
}
if ($field['type'] == 'link_field') {
$form['posterimage_field']['#description'] .= ' ' . t('Images referenced by this field will be used as poster image by default.');
}
}
if (!empty($trackfields)) {
$form['tracks_field'] = array(
'#type' => 'select',
'#title' => t('Field containing text tracks'),
'#default_value' => $settings['tracks_field'],
'#options' => $trackfields,
'#description' => t('VTT text tracks can be read from a separate field for this content type.'),
'#empty_value' => '',
);
if ($field['type'] == 'file') {
$form['tracks_field']['#description'] .= ' ' . t('VTT files uploaded to this field will be used by default.');
}
if ($field['type'] == 'link_field') {
$form['tracks_field']['#description'] .= ' ' . t('VTT files referenced by this field will be used by default.');
}
}
return $form;
}
function videojs_field_formatter_settings_form_validate($form, &$form_state) {
$value = drupal_array_get_nested_value($form_state['values'], $form['#parents']);
$options = videojs_utility::getDisplaySettingsFormResults($value);
$value = array_merge($value, $options);
// The fields need to be both entered or both empty
if (empty($value['width']) != empty($value['height'])) {
form_error($form[empty($value['width']) ? 'height' : 'width'], t('The width and height field need to be both set or both empty.'));
}
if (empty($value['width'])) {
$value['width'] = NULL;
$value['height'] = NULL;
}
drupal_array_set_nested_value($form_state['values'], $form['#parents'], $value);
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function videojs_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$output = t('Player dimensions: @widthxheight', array(
'@widthxheight' => !empty($settings['width']) && !empty($settings['height']) ? $settings['width'] . 'x' . $settings['height'] : t('default'),
));
if ($settings['centeredplaybutton']) {
$output .= '<br/>' . t('Center the big play button');
}
if ($settings['loop']) {
$output .= '<br/>' . t('Loop playback');
}
if ($settings['autoplay']) {
$output .= '<br/>' . t('Auto-play files on page load');
}
if ($settings['hidecontrols']) {
$output .= '<br/>' . t('Hide controls');
}
if (!empty($settings['preload'])) {
$output .= '<br/>' . t('Preload behavior') . ': ' . check_plain($settings['preload']);
}
if (!empty($settings['posterimage_field'])) {
$imageinstance = field_info_instance($instance['entity_type'], $settings['posterimage_field'], $instance['bundle']);
if ($imageinstance != NULL) {
$output .= '<br/>';
$output .= t('Poster image field') . ': ' . check_plain($imageinstance['label']);
}
}
if (module_exists('image')) {
$output .= '<br/>';
$image_styles = image_style_options(FALSE);
if (isset($image_styles[$settings['posterimage_style']])) {
$output .= t('Poster image style') . ': ' . check_plain($image_styles[$settings['posterimage_style']]);
}
else {
$output .= t('Poster image style') . ': ' . t('None');
}
}
return $output;
}
/**
* Add the Video.js library to the page.
*/
function videojs_add($add = TRUE) {
$added =& drupal_static(__FUNCTION__);
$path = videojs_get_path();
$remote = strpos($path, '://') !== FALSE || strncmp('//', $path, 2) === 0;
$jsdata = $path . '/video.js';
$jsopts = array(
'group' => JS_LIBRARY,
'preprocess' => !$remote,
'type' => $remote ? 'external' : 'file',
'weight' => 1,
);
$cssdata = $path . '/video-js.css';
$cssopts = array(
'preprocess' => !$remote,
'type' => $remote ? 'external' : 'file',
);
$swfdata = 'videojs.options.flash.swf = "' . file_create_url($path . '/video-js.swf') . '"';
$swfopts = array(
'group' => JS_LIBRARY,
'type' => 'inline',
'weight' => 5,
);
if ($add && !$added) {
drupal_add_js($jsdata, $jsopts);
drupal_add_css($cssdata, $cssopts);
drupal_add_js($swfdata, $swfopts);
$added = TRUE;
}
return array(
'js' => array(
$jsdata => $jsopts,
$swfdata => $swfopts,
),
'css' => array(
$cssdata => $cssopts,
),
);
}
/**
* Return the version of Video.js installed.
*
* @param $path
* The path to check for a Video.js installation. This can be a local path
* like sites/all/libraries/video-js or a remote path like
* http://mycdn.com/videojs. Do not add a trailing slash.
* Defaults to videojs_directory when using the local file path location
* or whatever location the Libraries API determines.
*
* @return
* The version found or NULL if no version found.
*/
function videojs_get_version($path = NULL) {
$version = NULL;
if (!isset($path)) {
// Don't hit the network for each call when using CDN.
if (variable_get('videojs_location', 'cdn') === 'cdn') {
return videojs_utility::getCdnVersion();
}
$path = videojs_get_path();
}
// When admins specify a protocol-relative URL, add http because file_get_contents doesn't understand it.
if (strncmp('//', $path, 2) === 0) {
$path = 'http:' . $path;
}
// Don't use file_exists() because it doesn't work with URLs.
// Now admins can also refer to directories like http://mycdn.com/videojs.
$contents = @file_get_contents($path . '/video.js', FALSE, NULL, 0, 400);
if (!empty($contents)) {
$matches = array();
if (preg_match(videojs_utility::VERSION_REGEX, $contents, $matches)) {
$version = $matches[1];
}
}
return $version;
}
/**
* Return the configured path or URL of Video.js.
*
* The validity of the path is not checked.
*
* @return string|bool
* The path or URL to video js, without a filename.
* FALSE when the path can't be determined.
*/
function videojs_get_path() {
switch (variable_get('videojs_location', 'cdn')) {
case 'path':
return variable_get('videojs_directory', 'sites/all/libraries/video-js');
case 'libraries':
if (!module_exists('libraries')) {
return FALSE;
}
return libraries_get_path('video-js');
case 'cdn':
default:
$cdnversion = videojs_utility::getCdnVersion();
return videojs_utility::CDN_HOST . $cdnversion;
}
}
/**
* Implements hook_libraries_info().
*/
function videojs_libraries_info() {
$libraries = array();
$libraries['video-js'] = array(
'name' => 'Video.js',
'vendor url' => 'http://videojs.com',
'download url' => 'http://videojs.com',
'version arguments' => array(
'file' => 'video.js',
'pattern' => videojs_utility::VERSION_REGEX,
'lines' => 2,
'cols' => 50,
),
'versions' => array(
'2' => array(
'files' => array(
'js' => array(
'video.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.css',
),
),
),
'3' => array(
'files' => array(
'js' => array(
'video.min.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.min.css',
),
),
'variants' => array(
'source' => array(
'files' => array(
'js' => array(
'video.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.css',
),
),
'minified' => array(
'files' => array(
'js' => array(
'video.min.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.min.css',
),
),
),
),
),
),
'4' => array(
'files' => array(
'js' => array(
'video.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.css',
),
),
'variants' => array(
'source' => array(
'files' => array(
'js' => array(
'video.dev.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.css',
),
),
'minified' => array(
'files' => array(
'js' => array(
'video.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.css',
),
),
),
),
),
),
'5' => array(
'files' => array(
'js' => array(
'video.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.css',
),
),
'variants' => array(
'source' => array(
'minified' => array(
'files' => array(
'js' => array(
'video.min.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.min.css',
),
),
),
),
),
),
'6' => array(
'files' => array(
'js' => array(
'video.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.css',
),
),
'variants' => array(
'source' => array(
'minified' => array(
'files' => array(
'js' => array(
'video.min.js' => array(
'group' => JS_LIBRARY,
),
),
'css' => array(
'video-js.min.css',
),
),
),
),
),
),
),
);
return $libraries;
}
/**
* Implements hook_file_mimetype_mapping_alter().
*
* Adds the vtt, webm and weba extensions.
*/
function videojs_file_mimetype_mapping_alter(&$mapping) {
if (!isset($mapping['extensions']['vtt'])) {
$mapping['mimetypes']['vtt'] = 'text/vtt';
$mapping['extensions']['vtt'] = 'vtt';
}
if (!isset($mapping['extensions']['webm'])) {
$mapping['mimetypes']['webm'] = 'video/webm';
$mapping['extensions']['webm'] = 'webm';
}
if (!isset($mapping['extensions']['weba'])) {
$mapping['mimetypes']['weba'] = 'audio/weba';
$mapping['extensions']['weba'] = 'weba';
}
}
Functions
Name | Description |
---|---|
videojs_add | Add the Video.js library to the page. |
videojs_field_formatter_info | Implements hook_field_formatter_info(). |
videojs_field_formatter_settings_form | Implements hook_field_formatter_settings_form(). |
videojs_field_formatter_settings_form_validate | |
videojs_field_formatter_settings_summary | Implements hook_field_formatter_settings_summary(). |
videojs_field_formatter_view | Implements hook_field_formatter_view(). |
videojs_file_mimetype_mapping_alter | Implements hook_file_mimetype_mapping_alter(). |
videojs_get_path | Return the configured path or URL of Video.js. |
videojs_get_version | Return the version of Video.js installed. |
videojs_libraries_info | Implements hook_libraries_info(). |
videojs_menu | Implements hook_menu(). |
videojs_theme | Implements hook_theme(). |