video_embed_field.handlers.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. <?php
  2. /**
  3. * Provide some handlers for video embed field
  4. * Other modules can implement the hook_video_embed_handler_info to provide more handlers
  5. */
  6. /**
  7. * Implements hook_video_embed_handler_info().
  8. */
  9. function video_embed_field_video_embed_handler_info() {
  10. $handlers = array();
  11. $handlers['youtube'] = array(
  12. 'title' => 'Youtube',
  13. 'function' => 'video_embed_field_handle_youtube',
  14. 'thumbnail_function' => 'video_embed_field_handle_youtube_thumbnail',
  15. 'data_function' => 'video_embed_field_handle_youtube_data',
  16. 'form' => 'video_embed_field_handler_youtube_form',
  17. 'domains' => array(
  18. 'youtube.com',
  19. 'youtu.be',
  20. ),
  21. 'defaults' => array(
  22. 'width' => '640px',
  23. 'height' => '360px',
  24. 'autoplay' => 0,
  25. 'hd' => 1,
  26. 'rel' => 0,
  27. 'autohide' => 2,
  28. 'showinfo' => 1,
  29. 'modestbranding' => 0,
  30. 'theme' => 'dark',
  31. 'iv_load_policy' => 1,
  32. ),
  33. );
  34. $handlers['vimeo'] = array(
  35. 'title' => 'Vimeo',
  36. 'function' => 'video_embed_field_handle_vimeo',
  37. 'thumbnail_function' => 'video_embed_field_handle_vimeo_thumbnail',
  38. 'data_function' => 'video_embed_field_handle_vimeo_data',
  39. 'form' => 'video_embed_field_handler_vimeo_form',
  40. 'domains' => array(
  41. 'vimeo.com',
  42. ),
  43. 'defaults' => array(
  44. 'width' => '640px',
  45. 'height' => '360px',
  46. 'color' => '00adef',
  47. 'portrait' => 1,
  48. 'title' => 1,
  49. 'byline' => 1,
  50. 'autoplay' => 0,
  51. 'loop' => 0,
  52. ),
  53. );
  54. return $handlers;
  55. }
  56. /**
  57. * Helper function to get the youtube video's id
  58. * Returns false if it doesn't parse for wahtever reason
  59. */
  60. function _video_embed_field_get_youtube_id($url) {
  61. // Find the ID of the video they want to play from the url
  62. if (stristr($url, 'http://')) {
  63. $url = substr($url, 7);
  64. }
  65. elseif (stristr($url, 'https://')) {
  66. $url = substr($url, 8);
  67. }
  68. if (stristr($url, 'playlist')) {
  69. //Playlists need the appended ampersand to take the options properly.
  70. $url = $url . '&';
  71. $pos = strripos($url, '?list=');
  72. if ($pos !== FALSE) {
  73. $pos2 = stripos($url, '&');
  74. $pos2++;
  75. }
  76. else {
  77. return FALSE;
  78. }
  79. }
  80. //Alternate playlist link
  81. elseif (stristr($url, 'view_play_list')) {
  82. $url = $url . '&';
  83. //All playlist ID's are prepended with PL. view_play_list links allow you to not have that, though.
  84. if (!stristr($url, '?p=PL')) {
  85. $url = substr_replace($url, 'PL', strpos($url, '?p=') + 3, 0);
  86. }
  87. //Replace the links format with the embed format
  88. $url = str_ireplace('play_list?p=', 'videoseries?list=', $url);
  89. $pos = strripos($url, 'videoseries?list=');
  90. if ($pos !== FALSE) {
  91. $pos2 = stripos($url, '&');
  92. $pos2++;
  93. }
  94. else {
  95. return FALSE;
  96. }
  97. }
  98. else {
  99. $pos = strripos($url, 'v=');
  100. if ($pos !== FALSE) {
  101. $pos += 2;
  102. $pos2 = stripos($url, '&', $pos);
  103. $pos_hash = stripos($url, '#', $pos);
  104. $pos2 = _video_embed_get_min($pos2, $pos_hash);
  105. }
  106. else {
  107. $pos = strripos($url, '/');
  108. if ($pos !== FALSE) {
  109. $pos++;
  110. $pos2 = stripos($url, '?', $pos);
  111. $pos_hash = stripos($url, '#', $pos);
  112. $pos2 = _video_embed_get_min($pos2, $pos_hash);
  113. }
  114. }
  115. }
  116. if ($pos === FALSE) {
  117. return FALSE;
  118. }
  119. else {
  120. if ($pos2 > 0) {
  121. $id = substr($url, $pos, $pos2 - $pos);
  122. }
  123. else {
  124. $id = substr($url, $pos);
  125. }
  126. }
  127. return $id;
  128. }
  129. /**
  130. * Handler for Youtube videos.
  131. */
  132. function video_embed_field_handle_youtube($url, $settings) {
  133. $output = array();
  134. //Grab the minutes and seconds, and just convert it down to seconds
  135. preg_match('/#t=((?P<min>\d+)m)?((?P<sec>\d+)s)?/', $url, $matches);
  136. //Give it some default data in case there is no #t=...
  137. $matches += array(
  138. "min" => 0,
  139. "sec" => 0,
  140. );
  141. $time = ($matches["min"] * 60) + $matches["sec"];
  142. $settings['start'] = $time;
  143. $id = _video_embed_field_get_youtube_id($url);
  144. if (!$id) {
  145. // We can't decode the URL - just return the URL as a link
  146. $output['#markup'] = l($url, $url);
  147. return $output;
  148. }
  149. // Construct the embed code
  150. $settings['wmode'] = 'opaque';
  151. $settings_str = _video_embed_code_get_settings_str($settings);
  152. $output['#markup'] = '<iframe width="' . $settings['width'] . '" height="' . $settings['height'] . '" src="//www.youtube.com/embed/' . $id . '?' . $settings_str . '" frameborder="0" allowfullscreen></iframe>';
  153. return $output;
  154. }
  155. /**
  156. * Get the thumbnail url for youtube videos
  157. */
  158. function video_embed_field_handle_youtube_thumbnail($video_url) {
  159. $info = array();
  160. $id = _video_embed_field_get_youtube_id($video_url);
  161. //Playlist
  162. if (stristr($id, '?list=')) {
  163. //Strip out all but the ID, including the PL behind the ID.
  164. $start = strpos($id, '?list=PL') + 8;
  165. $length = strpos($id, '&') - $start;
  166. $id = substr($id, $start, $length);
  167. $info['id'] = $id;
  168. //Playlist info is stored in XML. The thumbnail is in there.
  169. $xml = drupal_http_request('http://gdata.youtube.com/feeds/api/playlists/' . $id);
  170. if (!isset($xml->error)) {
  171. $xml = new SimpleXMLElement($xml->data);
  172. $media = $xml->children('http://search.yahoo.com/mrss/');
  173. if ($media->group->thumbnail && $media->group->thumbnail[0]->attributes()) {
  174. $attrs = $media->group->thumbnail[0]->attributes();
  175. $info['url'] = (string) $attrs['url'];
  176. }
  177. }
  178. }
  179. //Regular video
  180. elseif ($id) {
  181. $info['id'] = $id;
  182. $info['url'] = 'http://img.youtube.com/vi/' . $id . '/0.jpg';
  183. }
  184. return $info;
  185. }
  186. /**
  187. * Get video data for a YouTube video URL
  188. *
  189. * @param string $url
  190. * A YouTube video URL to get data for
  191. *
  192. * @return array|false $data
  193. * An array of video data, or FALSE if unable to fetch data
  194. */
  195. function video_embed_field_handle_youtube_data($url) {
  196. $data = array();
  197. // Get YouTube video ID from URL
  198. $id = _video_embed_field_get_youtube_id($url);
  199. if ($id) {
  200. $response = drupal_http_request('http://gdata.youtube.com/feeds/api/videos/' . $id . '?v=2&alt=json');
  201. if (!isset($response->error)) {
  202. $data = json_decode($response->data);
  203. $data = isset($data->entry) ? (array) $data->entry : (array) $data->feed;
  204. return _video_embed_field_clean_up_youtube_data($data);
  205. }
  206. }
  207. return FALSE;
  208. }
  209. /**
  210. * Flatten out some unnecessary nesting in the youtube data
  211. */
  212. function _video_embed_field_clean_up_youtube_data($data) {
  213. //make things a bit nicer for people trying to use the data
  214. foreach ($data as $key => $value) {
  215. if (is_object($value)) {
  216. $temp = (array) $value;
  217. if (isset($temp['$t'])) {
  218. $data[$key] = $temp['$t'];
  219. }
  220. else {
  221. $data[$key] = _video_embed_field_clean_up_youtube_data($temp);
  222. }
  223. }
  224. elseif (is_array($value)) {
  225. $data[$key] = _video_embed_field_clean_up_youtube_data($value);
  226. }
  227. if ($key === 'category') {
  228. $terms = array();
  229. foreach ($data[$key] as $value) {
  230. if (isset($value['scheme']) && $value['scheme'] == 'http://schemas.google.com/g/2005#kind') {
  231. continue;
  232. }
  233. if (isset($value['term'])) {
  234. $terms[] = $value['term'];
  235. }
  236. }
  237. $data['terms'] = $terms;
  238. }
  239. }
  240. return $data;
  241. }
  242. /**
  243. * Defines the form elements for the Youtube configuration form.
  244. */
  245. function video_embed_field_handler_youtube_form($defaults) {
  246. $form = array();
  247. $form['width'] = array(
  248. '#type' => 'textfield',
  249. '#size' => '5',
  250. '#title' => t('Player Width'),
  251. '#description' => t('The width of the youtube player.'),
  252. '#default_value' => $defaults['width'],
  253. );
  254. $form['height'] = array(
  255. '#type' => 'textfield',
  256. '#size' => '5',
  257. '#title' => t('Player Height'),
  258. '#description' => t('The height of the youtube player.'),
  259. '#default_value' => $defaults['height'],
  260. );
  261. $form['theme'] = array(
  262. '#type' => 'select',
  263. '#options' => array(
  264. 'dark' => t('Dark'),
  265. 'light' => t('Light'),
  266. ),
  267. '#title' => t('Player theme'),
  268. '#default_value' => $defaults['theme'],
  269. );
  270. $form['autoplay'] = array(
  271. '#type' => 'checkbox',
  272. '#title' => t('Autoplay'),
  273. '#description' => t('Play the video immediately.'),
  274. '#default_value' => $defaults['autoplay'],
  275. );
  276. $form['hd'] = array(
  277. '#type' => 'checkbox',
  278. '#title' => t('Use HD'),
  279. '#description' => t('Attempt to play the video in HD if available.'),
  280. '#default_value' => $defaults['hd'],
  281. );
  282. $form['rel'] = array(
  283. '#type' => 'checkbox',
  284. '#title' => t('Show related videos'),
  285. '#description' => t('Show related videos after the video is finished playing.'),
  286. '#default_value' => $defaults['rel'],
  287. );
  288. $form['showinfo'] = array(
  289. '#type' => 'checkbox',
  290. '#title' => t('Show info'),
  291. '#description' => t('Display information like the video title and rating before the video starts playing.'),
  292. '#default_value' => $defaults['showinfo'],
  293. );
  294. $form['modestbranding'] = array(
  295. '#type' => 'checkbox',
  296. '#title' => t('Hide Youtube logo'),
  297. '#description' => t('Hide the Youtube logo button on the player'),
  298. '#default_value' => $defaults['modestbranding'],
  299. );
  300. $form['iv_load_policy'] = array(
  301. '#type' => 'radios',
  302. '#options' => array(
  303. 1 => t('Show video annotations.'),
  304. 3 => t('Hide video annotations.'),
  305. ),
  306. '#title' => t('Display annotations'),
  307. '#description' => t('Controls the display of annotations over the video content. Only works when using the flash player.'),
  308. '#default_value' => $defaults['iv_load_policy'],
  309. );
  310. $form['autohide'] = array(
  311. '#type' => 'radios',
  312. '#options' => array(
  313. 0 => t('The video progress bar and player controls will be visible throughout the video.'),
  314. 1 => t('Automatically slide the video progress bar and the player controls out of view a couple of seconds after the video starts playing. They will only reappear if the user moves her mouse over the video player or presses a keyboard key.'),
  315. 2 => t('The video progress bar will fade out but the player controls (play button, volume control, etc.) remain visible.'),
  316. ),
  317. '#title' => t('Autohide progress bar and the player controls'),
  318. '#description' => t('Controls the autohide behavior of the youtube player controls.'),
  319. '#default_value' => $defaults['autohide'],
  320. );
  321. return $form;
  322. }
  323. /**
  324. * Helper function to get the Vimeo video's ID
  325. *
  326. * @param string $url
  327. * A Vimeo video URL to get the ID of
  328. *
  329. * @return integer|false $id
  330. * The video ID, or FALSE if unable to get the video ID
  331. */
  332. function _video_embed_field_get_vimeo_id($url) {
  333. $pos = strripos($url, '/');
  334. if ($pos != FALSE) {
  335. $pos += 1;
  336. return (int) substr($url, $pos);
  337. }
  338. return FALSE;
  339. }
  340. /**
  341. * Handler for Vimeo videos.
  342. */
  343. function video_embed_field_handle_vimeo($url, $settings) {
  344. // Get ID of video from URL
  345. $id = _video_embed_field_get_vimeo_id($url);
  346. if (!$id) {
  347. return array(
  348. '#markup' => l($url, $url),
  349. );
  350. }
  351. // Construct the embed code
  352. $settings['portrait'] = 0;
  353. $settings_str = _video_embed_code_get_settings_str($settings);
  354. return array(
  355. '#markup' => '<iframe width="' . $settings['width'] . '" height="' . $settings['height'] . '" src="//player.vimeo.com/video/' . $id .
  356. '?' . $settings_str . '" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowfullscreen></iframe>',
  357. );
  358. }
  359. /**
  360. * Get the thumbnail url for youtube videos
  361. */
  362. function video_embed_field_handle_vimeo_thumbnail($url) {
  363. // Get ID of video from URL
  364. $id = _video_embed_field_get_vimeo_id($url);
  365. $info = array(
  366. 'id' => $id,
  367. );
  368. $response = drupal_http_request('http://vimeo.com/api/v2/video/' . $id . '.php');
  369. if (!isset($response->error)) {
  370. $response = unserialize($response->data);
  371. $video = current($response);
  372. $image_url = $video['thumbnail_large'];
  373. $info['url'] = $image_url;
  374. }
  375. return $info;
  376. }
  377. /**
  378. * Get video data for a Vimeo video URL
  379. *
  380. * @param string $url
  381. * A Vimeo video URL to get data for
  382. *
  383. * @return array|false $data
  384. * An array of video data, or FALSE if unable to fetch data
  385. */
  386. function video_embed_field_handle_vimeo_data($url) {
  387. // Get ID of video from URL
  388. $id = _video_embed_field_get_vimeo_id($url);
  389. if ($id) {
  390. $response = drupal_http_request('http://vimeo.com/api/v2/video/' . $id . '.php');
  391. if (!isset($response->error)) {
  392. $response = unserialize($response->data);
  393. return (array) current($response);
  394. }
  395. }
  396. return FALSE;
  397. }
  398. /**
  399. * Defines the form elements for the Vimeo configuration form.
  400. */
  401. function video_embed_field_handler_vimeo_form($defaults) {
  402. $form = array();
  403. $form['width'] = array(
  404. '#type' => 'textfield',
  405. '#size' => '5',
  406. '#title' => t('Player Width'),
  407. '#description' => t('The width of the vimeo player.'),
  408. '#default_value' => $defaults['width'],
  409. );
  410. $form['height'] = array(
  411. '#type' => 'textfield',
  412. '#size' => '5',
  413. '#title' => t('Player Height'),
  414. '#description' => t('The height of the vimeo player.'),
  415. '#default_value' => $defaults['height'],
  416. );
  417. $form['color'] = array(
  418. '#type' => 'select',
  419. '#options' => array(
  420. '00adef' => t('Blue'),
  421. 'ff9933' => t('Orange'),
  422. 'c9ff23' => t('Lime'),
  423. 'ff0179' => t('Fuschia'),
  424. 'ffffff' => t('White'),
  425. ),
  426. '#title' => t('Player Color'),
  427. '#description' => t('The color to use on the vimeo player.'),
  428. '#default_value' => $defaults['color'],
  429. );
  430. $form['portrait'] = array(
  431. '#type' => 'checkbox',
  432. '#title' => t('Overlay Author Thumbnail'),
  433. '#description' => t('Overlay the author\'s thumbnail before the video is played.'),
  434. '#default_value' => $defaults['portrait'],
  435. );
  436. $form['title'] = array(
  437. '#type' => 'checkbox',
  438. '#title' => t('Overlay Video\'s Title'),
  439. '#description' => t('Overlay the video\'s title before the video is played.'),
  440. '#default_value' => $defaults['title'],
  441. );
  442. $form['byline'] = array(
  443. '#type' => 'checkbox',
  444. '#title' => t('Overlay Video\'s Byline'),
  445. '#description' => t('Overlay the video\'s description before the video is played.'),
  446. '#default_value' => $defaults['byline'],
  447. );
  448. $form['overridable'] = array(
  449. '#prefix' => '<p class="note"><strong>' . t('Note') . ': </strong><em>',
  450. '#markup' => t('Color, portrait, title and byline can be restricted by Vimeo Plus videos.
  451. Such videos will ignore these settings.'),
  452. '#suffix' => '</em></p>',
  453. );
  454. $form['autoplay'] = array(
  455. '#type' => 'checkbox',
  456. '#title' => t('Autoplay'),
  457. '#description' => t('Play the video immediately.'),
  458. '#default_value' => $defaults['autoplay'],
  459. );
  460. $form['loop'] = array(
  461. '#type' => 'checkbox',
  462. '#title' => t('Loop'),
  463. '#description' => t('Loop the video\'s playback'),
  464. '#default_value' => $defaults['loop'],
  465. );
  466. return $form;
  467. }
  468. /**
  469. * Calculate the min index for use in finding the id of a youtube video
  470. */
  471. function _video_embed_get_min($pos1, $pos2) {
  472. if (!$pos1) {
  473. return $pos2;
  474. }
  475. elseif (!$pos2) {
  476. return $pos1;
  477. }
  478. else {
  479. return min($pos1, $pos2);
  480. }
  481. }