t('YouTube'), ); return $info; } /** * Implements hook_stream_wrappers(). */ function media_youtube_stream_wrappers() { return array( 'youtube' => array( 'name' => t('YouTube videos'), 'class' => 'MediaYouTubeStreamWrapper', 'description' => t('Videos provided by YouTube.'), '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(). * * Register the video/youtube mimetype. */ function media_youtube_file_mimetype_mapping_alter(&$mapping) { $mapping['mimetypes'][] = 'video/youtube'; } /** * 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()) { 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'] = '
'; $empty = FALSE; $files = array(); if (!isset($search['entry'])) { $empty = TRUE; } else { foreach ($search['entry'] as $video) { try { $uri = media_parse_to_uri($video['link'][0]['@attributes']['href']); } 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'; if (!isset($file->fid)) { $file->fid = 0; } media_browser_build_media_item($file); $file->preview = l($file->preview, 'media/browser', array( 'html' => TRUE, 'attributes' => array( 'data-uri' => $uri, ), 'query' => array('render' => 'media-popup', 'uri' => $uri), )); $form['videos'][$uri] = array( '#markup' => $file->preview, '#prefix' => '
  • ', '#suffix' => '
  • ', ); $files[$uri] = $file; } } if (!count($files)) { $empty= TRUE; } if ($empty) { $form['empty'] = array( '#markup' => '
    ' . t('No videos match your search criteria. Please try again.') . '
    ', ); } $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 = $form['#validators']; 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. // @TODO: media_access() is a wrapper for file_entity_access(). Switch to the // new function when Media 1.x is deprecated. if (media_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'; } } /** * @TODO: Document this function. */ function media_youtube_video_search($options = array()) { $options['v'] = 2; $request = drupal_http_request(url(MEDIA_YOUTUBE_REST_API, array('query' => $options))); if (!isset($request->error)) { $entry = simplexml_load_string($request->data); } else { throw new Exception("Error Processing Request. (Error: {$request->code}, {$request->error})"); //if request wasn't successful, create object for return to avoid errors $entry = new SimpleXMLElement(); } return media_youtube_unserialize_xml($entry); } /** * 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]; }