media_youtube.module in Media: YouTube 7.2
Same filename and directory in other branches
Provides a stream wrapper and formatters appropriate for accessing and displaying YouTube videos.
File
media_youtube.moduleView source
<?php
/**
* @file
* Provides a stream wrapper and formatters appropriate for accessing and
* displaying YouTube videos.
*/
/**
* This is the rest point for the YouTube api.
*
* Avoid using the gdata api url when possible. Too many calls will result in
* throttling and 403 errors.
*/
define('MEDIA_YOUTUBE_REST_API', variable_get('media_youtube_api_url', ''));
// Load all YouTube file formatters.
require_once dirname(__FILE__) . '/includes/media_youtube.formatters.inc';
/**
* Implements hook_media_internet_providers().
*/
function media_youtube_media_internet_providers() {
return array(
'MediaInternetYouTubeHandler' => array(
'title' => t('YouTube'),
),
);
}
/**
* Implements hook_stream_wrappers().
*/
function media_youtube_stream_wrappers() {
return array(
'youtube' => array(
'name' => t('YouTube videos'),
'class' => 'MediaYouTubeStreamWrapper',
'description' => t('Remote videos hosted on the YouTube video-sharing website.'),
'type' => STREAM_WRAPPERS_READ_VISIBLE,
),
);
}
/**
* Implements hook_theme().
*/
function media_youtube_theme($existing, $type, $theme, $path) {
return array(
'media_youtube_video' => array(
'variables' => array(
'uri' => NULL,
'options' => array(),
),
'file' => 'media_youtube.theme.inc',
'path' => $path . '/themes',
'template' => 'media-youtube-video',
),
);
}
/**
* Implements hook_media_parse().
*
* @todo This hook should be deprecated. Refactor Media module to not call it
* any more, since media_internet should be able to automatically route to the
* appropriate handler.
*/
function media_youtube_media_parse($embed_code) {
$handler = new MediaInternetYouTubeHandler($embed_code);
return $handler
->parse($embed_code);
}
/**
* Implements hook_file_mimetype_mapping_alter().
*/
function media_youtube_file_mimetype_mapping_alter(&$mapping) {
$mapping['mimetypes'][] = 'video/youtube';
}
/**
* Implements hook_ctools_plugin_api().
*/
function media_youtube_ctools_plugin_api($module, $api) {
if ($module == 'file_entity' && $api == 'file_default_displays') {
return array(
'version' => 1,
);
}
}
/**
* YouTube search tab for the Media browser.
*/
/**
* Implements hook_media_browser_plugin_info().
*
* Commented out for release versions, active in dev versions. To enable the
* YouTube media browser tab, uncomment this function.
*/
function media_youtube_media_browser_plugin_info() {
$info['youtube'] = array(
'title' => t('YouTube'),
'class' => 'MediaYouTubeBrowser',
);
return $info;
}
/**
* Provides a form for adding media items from YouTube search.
*/
function media_youtube_add($form, &$form_state = array()) {
if (strlen(variable_get('media_youtube_api_key', '')) == 0) {
$form = array();
$form['message'] = array(
'#markup' => t('YouTube Data API v3 is required. You can obtain your key ' . '<a href="https://developers.google.com/youtube/v3/getting-started">' . 'here</a>. Then you need to put it in the configurations page click <a href="@url"> here ' . '</a> to go the configuration page.', array(
'@url' => url('admin/config/media/media-youtube'),
)),
);
$form['actions'] = array(
'#type' => 'actions',
);
return $form;
}
module_load_include('inc', 'media', 'includes/media.browser');
// Our search term can come from the form, or from the pager.
$term = isset($form_state['input']['search']) ? $form_state['input']['search'] : (isset($_GET['search']) ? $_GET['search'] : '');
$form['search'] = array(
'#type' => 'textfield',
'#title' => t('Search'),
'#description' => t('Input a phrase or tags to search.'),
'#default_value' => $term,
);
$form['apply'] = array(
'#type' => 'button',
'#value' => t('Apply'),
);
// This is our half-assed pager.
$page = isset($_GET['page-yt']) ? $_GET['page-yt'] : 0;
if (isset($form_state['input']['search'])) {
// Reset the pager when we press apply.
$page = 0;
}
if (!empty($term)) {
$search = media_youtube_video_search(array(
'q' => $term,
'max-results' => 12,
'start-index' => $page * 12 + 1,
));
}
$form['videos']['#prefix'] = '<div id="container"><div id="scrollbox"><ul id="media-browser-library-list" class="media-list-thumbnails">';
$form['videos']['#suffix'] = '</ul><div id="status"></div></div></div>';
$empty = FALSE;
$files = array();
if (!isset($search->items)) {
$empty = TRUE;
}
else {
// $search['entry'] is different depending on whether there is a single
// result or multiple results. So normalise it.
$videos = $search->items;
foreach ($videos as $video) {
if ($video->id->kind == "youtube#video") {
try {
$uri = 'youtube://v/' . $video->id->videoId;
} catch (Exception $e) {
// Ignore invalid videos.
continue;
}
// Create a temporary file object for our retrieved video.
$file = file_uri_to_object($uri);
$file->type = 'video';
$file->filemime = 'video/youtube';
if (!isset($file->fid)) {
$file->fid = 0;
}
media_browser_build_media_item($file);
$attributes = array(
'data-uri' => $uri,
'class' => array(
'media-youtube-wrapper',
),
);
$form['videos'][$uri] = array(
'#markup' => $file->preview,
'#prefix' => '<li' . drupal_attributes($attributes) . '>',
'#suffix' => '</li>',
);
$files[$uri] = $file;
}
}
}
if (!count($files)) {
$empty = TRUE;
}
if ($empty) {
$form['empty'] = array(
'#markup' => '<div class="empty-message">' . t('No videos match your search criteria. Please try again.') . '</div>',
);
}
$query = $_GET;
if ($term !== '') {
$query['search'] = $term;
}
$dest = $query['q'];
unset($query['q']);
$prev = $next = '';
if ($page) {
$query['page-yt'] = $page - 1;
$prev = l(t('previous'), $dest, array(
'query' => $query,
));
}
$query['page-yt'] = $page + 1;
if (!$empty) {
$next = l(t('next'), $dest, array(
'query' => $query,
));
}
$form['pager'] = array(
'#markup' => $prev . ' ' . $next,
);
$form['submitted-video'] = array(
'#type' => 'hidden',
'#default_value' => FALSE,
);
// Add the files to JS so that they are accessible inside the browser
drupal_add_js(array(
'media' => array(
'files' => $files,
),
), 'setting');
// Add media browser javascript and CSS.
drupal_add_js(drupal_get_path('module', 'media_youtube') . '/js/media-youtube.browser.js');
// @TODO: Remove deprecated library js and css. They're removed in Media,
// so let's comment out for now.
// drupal_add_js(drupal_get_path('module', 'media') . '/js/plugins/media.library.js');
// drupal_add_css(drupal_get_path('module', 'media') . '/js/plugins/media.library.css');
$form['actions'] = array(
'#type' => 'actions',
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
/**
* Allow stream wrappers to have their chance at validation.
*
* Any module that implements hook_media_parse will have an
* opportunity to validate this.
*
* @see media_parse_to_uri()
*/
function media_youtube_add_validate($form, &$form_state) {
if ($form_state['values']['op'] == t('Apply')) {
return;
}
$uri = $form_state['values']['submitted-video'];
try {
$file = file_uri_to_object($uri, TRUE);
} catch (Exception $e) {
form_set_error('url', $e
->getMessage());
return;
}
if (!$file->uri) {
form_set_error('url', t('Please select a video.'));
return;
}
$validators = isset($form['#validators']) ? $form['#validators'] : array();
if ($validators) {
// Check for errors. @see media_add_upload_validate calls file_save_upload().
// this code is ripped from file_save_upload because we just want the validation part.
// Call the validation functions specified by this function's caller.
$errors = file_validate($file, $validators);
if (!empty($errors)) {
$message = t('%uri could not be added.', array(
'%uri' => $uri,
));
if (count($errors) > 1) {
$message .= theme('item_list', array(
'items' => $errors,
));
}
else {
$message .= ' ' . array_pop($errors);
}
form_set_error('url', $message);
return FALSE;
}
}
// @TODO: Validate that if we have no $uri that this is a valid file to
// save. For instance, we may only be interested in images, and it would
// be helpful to let the user know they passed the HTML page containing
// the image accidentally. That would also save us from saving the file
// in the submit step.
// This is kinda a hack of the same.
// This should use the file_validate routines that the upload form users.
// We need to fix the media_parse_to_file routine to allow for a validation.
}
/**
* @TODO: Document this function.
*/
function media_youtube_add_submit($form, &$form_state) {
$uri = $form_state['values']['submitted-video'];
try {
// Save the remote file
$file = file_uri_to_object($uri, TRUE);
file_save($file);
} catch (Exception $e) {
form_set_error('url', $e
->getMessage());
return;
}
if (!$file->fid) {
form_set_error('url', t('The file %file could not be saved. An unknown error has occurred.', array(
'%file' => $uri,
)));
return;
}
else {
$form_state['file'] = $file;
}
// Redirect to the file edit page after submission.
if (media_youtube_access('update', $file)) {
$destination = array(
'destination' => 'admin/content/file',
);
if (isset($_GET['destination'])) {
$destination = drupal_get_destination();
unset($_GET['destination']);
}
$form_state['redirect'] = array(
'file/' . $file->fid . '/edit',
array(
'query' => $destination,
),
);
}
else {
$form_state['redirect'] = 'admin/content/file';
}
}
/**
* Determine if a user may perform the given operation on the specified file.
*
* Enables compatibility with Media 1.x and 2.x by providing a wrapper around
* both media_access() and file_entity_access().
*
* @return boolean
* TRUE if the operation may be performed, FALSE otherwise.
*
* @see media_access()
* @see file_entity_access()
*/
function media_youtube_access($op, $file = NULL, $account = NULL) {
if (function_exists('file_entity_access')) {
$access = file_entity_access($op, $file, $account);
}
elseif (function_exists('media_access')) {
$access = media_access($op, $account);
}
else {
$access = FALSE;
}
return $access;
}
/**
* @TODO: Document this function.
*/
function media_youtube_video_search($options = array()) {
$options['v'] = 3;
$options['key'] = variable_get('media_youtube_api_key', '');
$options['part'] = 'snippet';
$options['maxResults'] = variable_get('media_youtube_max_results', '5');
$request = drupal_http_request(url(MEDIA_YOUTUBE_REST_API, array(
'query' => $options,
)));
if (!isset($request->error)) {
$json = json_decode($request->data);
}
else {
throw new Exception("Error Processing Request. (Error: {$request->code}, {$request->error}, {$request->data})");
//if request wasn't successful, create object for return to avoid errors
//$entry = new SimpleXMLElement();
}
// return media_youtube_unserialize_xml($entry);
return $json;
}
/**
* Recursively converts a SimpleXMLElement object into an array.
*
* @param object $xml
* The original XML object.
*/
function media_youtube_unserialize_xml($xml) {
if ($xml instanceof SimpleXMLElement) {
$xml = (array) $xml;
}
if (is_array($xml)) {
foreach ($xml as $key => $item) {
$xml[$key] = media_youtube_unserialize_xml($item);
}
}
return $xml;
}
/**
* Check to ensure that a given id is valid.
*
* @param string $id
* The YouTube video id.
* @param boolean $refresh
* (Defaults to FALSE) If TRUE, then reset the value from the cache.
* @return boolean
* Returns TRUE if the video is valid.
*
* @TODO: How does this compare to MediaInternetYouTubeHandler's validId
* method, and can we refactor the code to rely on only one of them?
*/
function media_youtube_valid_id($id, $refresh = FALSE) {
$ids =& drupal_static(__FUNCTION__, array());
// Return our cached id if allowed, and it exists.
if (!$refresh && isset($ids[$id])) {
return $ids[$id];
}
elseif (!$refresh && !isset($ids[$id])) {
return $id;
}
elseif (!$refresh && ($cache = cache_get('media_youtube:id:' . $id, 'cache_media_xml'))) {
$ids[$id] = $cache->data;
return $ids[$id];
}
$url = url(MEDIA_YOUTUBE_REST_API . '/' . $id);
$response = drupal_http_request($url, array(
'method' => 'HEAD',
));
$ids[$id] = $response->code == 200;
cache_set('media_youtube:id:' . $id, $ids[$id], 'cache_media_xml', media_variable_get('xml_cache_expire', 3600));
return $ids[$id];
}
/**
* Implements hook_menu().
*
* Added to configure YouTube API KEY
*/
function media_youtube_menu() {
$items['admin/config/media/media-youtube'] = array(
'title' => "Media: YouTube",
'page callback' => 'drupal_get_form',
'page arguments' => array(
'media_youtube_settings_form',
),
'access arguments' => array(
'administer media browser',
),
// TODO: is this permission ok here ? (come from media module)
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
* Settings form.
*
* Added to configure YouTube API KEY
*/
function media_youtube_settings_form($form, &$form_state) {
$form['media_youtube_api_url'] = array(
'#type' => 'textfield',
'#title' => t('YouTube API Url'),
'#description' => t('YouTube API Url'),
'#default_value' => variable_get('media_youtube_api_url', ''),
);
$form['media_youtube_api_key'] = array(
'#type' => 'textfield',
'#title' => t('API key'),
'#description' => t('The Google API key has to be requested from the Google website. A Google account is needed too. See https://developers.google.com/youtube/v3/getting-started'),
'#default_value' => variable_get('media_youtube_api_key', ''),
);
$form['media_youtube_max_results'] = array(
'#type' => 'textfield',
'#title' => t('Maximum search results to display in media browser'),
'#description' => t('The <em>maxResults</em> parameter specifies the maximum number of items that should be returned in the result set. Acceptable values are 1 to 50, inclusive.'),
'#default_value' => variable_get('media_youtube_max_results', 5),
);
$form = system_settings_form($form);
return $form;
}
Functions
Constants
Name | Description |
---|---|
MEDIA_YOUTUBE_REST_API | This is the rest point for the YouTube api. |