video_embed_field.field.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. <?php
  2. /**
  3. * @file
  4. * Implement a video field.
  5. */
  6. /**
  7. * Implements hook_field_info().
  8. */
  9. function video_embed_field_field_info() {
  10. return array(
  11. 'video_embed_field' => array(
  12. 'label' => 'Video Embed',
  13. 'description' => 'Embed videos from youtube or vimeo',
  14. 'settings' => array(),
  15. 'instance_settings' => array(
  16. 'description_field' => 0,
  17. 'description_length' => 128,
  18. 'allowed_providers' => array_keys(video_embed_get_handlers()),
  19. ),
  20. 'default_widget' => 'video_embed_field_video',
  21. 'default_formatter' => 'video_embed_field',
  22. 'property_type' => 'video_embed_field',
  23. 'property_callbacks' => array('video_embed_field_property_info_callback'),
  24. ),
  25. );
  26. }
  27. /**
  28. * Property callback for the Entity Metadata framework.
  29. */
  30. function video_embed_field_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
  31. // Apply the default.
  32. entity_metadata_field_default_property_callback($info, $entity_type, $field, $instance, $field_type);
  33. // Finally add in instance specific property info.
  34. $name = $field['field_name'];
  35. $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
  36. $property['type'] = ($field['cardinality'] != 1) ? 'list<video_embed_field>' : 'video_embed_field';
  37. $property['property info'] = video_embed_field_data_property_info('Video embed');
  38. $property['getter callback'] = 'entity_metadata_field_verbatim_get';
  39. $property['setter callback'] = 'entity_metadata_field_verbatim_set';
  40. }
  41. /**
  42. * Defines info for the properties of the video_embed_field data structure.
  43. */
  44. function video_embed_field_data_property_info($name = NULL) {
  45. // Build an array of basic property information for video_embed_field.
  46. $properties = array(
  47. 'video_url' => array(
  48. 'label' => 'Video URL',
  49. 'type' => 'uri',
  50. 'setter callback' => 'entity_property_verbatim_set',
  51. ),
  52. 'thumbnail_path' => array(
  53. 'label' => 'Thumbnail path',
  54. 'type' => 'uri',
  55. 'getter callback' => 'entity_property_verbatim_get_url',
  56. ),
  57. 'description' => array(
  58. 'label' => 'Description',
  59. 'type' => 'text',
  60. 'setter callback' => 'entity_property_verbatim_set',
  61. ),
  62. );
  63. // Add the default values for each of the video_embed_field properties.
  64. foreach ($properties as $key => &$value) {
  65. $value += array(
  66. 'description' => !empty($name) ? t('!label of field %name', array('!label' => $value['label'], '%name' => $name)) : '',
  67. );
  68. }
  69. return $properties;
  70. }
  71. /**
  72. * Gets the property just as it is set in the data and converts to absolute url.
  73. */
  74. function entity_property_verbatim_get_url($data, array $options, $name, $type, $info) {
  75. $property = entity_property_verbatim_get($data, $options, $name, $type, $info);
  76. return file_create_url($property);
  77. }
  78. /**
  79. * Implements hook_field_instance_settings_form().
  80. */
  81. function video_embed_field_field_instance_settings_form($field, $instance) {
  82. $settings = $instance['settings'];
  83. $providers = video_embed_get_handlers();
  84. $allowed_providers = array();
  85. foreach ($providers as $provider_id => $definition) {
  86. $allowed_providers[$provider_id] = $definition['title'];
  87. }
  88. $form['allowed_providers'] = array(
  89. '#type' => 'checkboxes',
  90. '#title' => t('Select the allowed video providers'),
  91. '#options' => $allowed_providers,
  92. '#default_value' => isset($settings['allowed_providers']) ? $settings['allowed_providers'] : array(),
  93. '#weight' => 10,
  94. );
  95. $form['description_field'] = array(
  96. '#type' => 'checkbox',
  97. '#title' => t('Enable <em>Description</em> field'),
  98. '#default_value' => isset($settings['description_field']) ? $settings['description_field'] : '',
  99. '#description' => t('The description field allows users to enter a description about the video.'),
  100. '#weight' => 11,
  101. );
  102. $form['description_length'] = array(
  103. '#type' => 'textfield',
  104. '#title' => t('Max description length'),
  105. '#default_value' => isset($settings['description_length']) ? $settings['description_length'] : 128,
  106. '#weight' => 12,
  107. '#size' => 5,
  108. '#maxlength' => 5,
  109. '#states' => array(
  110. 'visible' => array(
  111. ':input[id="edit-instance-settings-description-field"]' => array('checked' => TRUE),
  112. ),
  113. ),
  114. );
  115. return $form;
  116. }
  117. /**
  118. * Implements hook_field_widget_info().
  119. */
  120. function video_embed_field_field_widget_info() {
  121. return array(
  122. 'video_embed_field_video' => array(
  123. 'label' => 'Video',
  124. 'description' => 'Provides a video embed field',
  125. 'field types' => array('video_embed_field'),
  126. 'settings' => array(),
  127. 'behaviors' => array(
  128. 'multiple values' => FIELD_BEHAVIOR_DEFAULT,
  129. 'default value' => FIELD_BEHAVIOR_DEFAULT,
  130. ),
  131. ),
  132. );
  133. }
  134. /**
  135. * Implements hook_field_widget_form().
  136. */
  137. function video_embed_field_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  138. // Don't need to check the type right now because we're only defining one.
  139. $element += array(
  140. '#type' => 'fieldset',
  141. );
  142. $element['video_url'] = array(
  143. '#type' => 'textfield',
  144. '#title' => t('Video URL'),
  145. '#attributes' => array('class' => array('video_embed_url')),
  146. '#attached' => array(
  147. 'css' => array(
  148. drupal_get_path('module', 'video_embed_field') . '/video_embed_field.form.css',
  149. ),
  150. ),
  151. '#default_value' => isset($items[$delta]['video_url']) ? $items[$delta]['video_url'] : '',
  152. '#required' => $element['#required'],
  153. '#maxlength' => 255,
  154. );
  155. // Add the description field if enabled.
  156. if (!empty($instance['settings']['description_field'])) {
  157. $element['description'] = array(
  158. '#type' => 'textfield',
  159. '#title' => t('Description'),
  160. '#default_value' => isset($items[$delta]['description']) ? $items[$delta]['description'] : '',
  161. '#description' => t('The description which may be used as a label.'),
  162. '#maxlength' => $instance['settings']['description_length'],
  163. );
  164. }
  165. return $element;
  166. }
  167. /**
  168. * Validates video URL.
  169. */
  170. function video_embed_field_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
  171. foreach ($items as $delta => $item) {
  172. if (!empty($item['video_url'])) {
  173. $item['video_url'] = trim($item['video_url']);
  174. if (stristr($item['video_url'], '.') && !stristr($item['video_url'], 'http://') && !stristr($item['video_url'], 'https://')) {
  175. $item['video_url'] = 'http://' . $item['video_url'];
  176. }
  177. $parts = parse_url($item['video_url']);
  178. if (!$parts || !isset($parts['host'])) {
  179. $errors[$field['field_name']][$langcode][$delta][] = array(
  180. 'error' => t('Invalid Url'),
  181. 'message' => t('Video: Invalid Video URL.', array('%name' => $instance['label'])),
  182. );
  183. }
  184. else {
  185. $host = $parts['host'];
  186. if (stripos($host, 'www.') > -1) {
  187. $host = substr($host, 4);
  188. }
  189. $domains = _video_embed_field_get_instance_provider_domains($instance);
  190. if (!array_key_exists($host, $domains)) {
  191. $errors[$field['field_name']][$langcode][$delta][] = array(
  192. 'error' => t('Unsupported Video Provider'),
  193. 'message' => t('%name: This video provider is not currently supported.', array('%name' => $instance['label'])),
  194. );
  195. }
  196. }
  197. }
  198. }
  199. }
  200. /**
  201. * Implements hook_field_presave().
  202. *
  203. * Download and save the thumbnail if it hasn't already been stored.
  204. * Get video data.
  205. */
  206. function video_embed_field_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
  207. foreach ($items as $delta => $item) {
  208. // Trim whitespace from the video URL.
  209. $items[$delta]['video_url'] = trim($item['video_url']);
  210. // Try to load thumbnail URL.
  211. $info = video_embed_field_thumbnail_url($item['video_url']);
  212. if (isset($info['url']) && $info['url']) {
  213. $thumb_url = $info['url'];
  214. $thumb_extension = pathinfo($thumb_url, PATHINFO_EXTENSION);
  215. $local_path = "public://video_embed_field_thumbnails/{$info['handler']}/{$info['id']}.$thumb_extension";
  216. $dirname = drupal_dirname($local_path);
  217. file_prepare_directory($dirname, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
  218. $response = drupal_http_request($thumb_url);
  219. if (!isset($response->error)) {
  220. file_save_data($response->data, $local_path, FILE_EXISTS_REPLACE);
  221. }
  222. else {
  223. @copy($thumb_url, $local_path);
  224. }
  225. $items[$delta]['thumbnail_path'] = $local_path;
  226. // Delete any image derivatives at the original image path.
  227. image_path_flush($local_path);
  228. }
  229. // Couldn't get the thumbnail for whatever reason.
  230. else {
  231. $items[$delta]['thumbnail_path'] = '';
  232. }
  233. // Try to load video data.
  234. $data = video_embed_field_get_video_data($item['video_url']);
  235. if (is_array($data) && !empty($data)) {
  236. $items[$delta]['video_data'] = serialize($data);
  237. }
  238. else {
  239. $items[$delta]['video_data'] = NULL;
  240. }
  241. }
  242. }
  243. /**
  244. * Implements hook_field_is_empty().
  245. */
  246. function video_embed_field_field_is_empty($item, $field) {
  247. return empty($item) || empty($item['video_url']) || $item['video_url'] === '';
  248. }
  249. /**
  250. * Implements hook_field_formatter_info().
  251. */
  252. function video_embed_field_field_formatter_info() {
  253. $info = array(
  254. 'video_embed_field' => array(
  255. 'label' => t('Video Player'),
  256. 'field types' => array('video_embed_field'),
  257. 'settings' => array(
  258. 'video_style' => 'normal',
  259. 'description' => 1,
  260. 'description_position' => 'bottom',
  261. ),
  262. ),
  263. 'video_embed_field_url' => array(
  264. 'label' => t('URL to Video'),
  265. 'field types' => array('video_embed_field'),
  266. 'settings' => array(),
  267. ),
  268. 'video_embed_field_thumbnail' => array(
  269. 'label' => t('Thumbnail Preview'),
  270. 'field types' => array('video_embed_field'),
  271. 'settings' => array(
  272. 'image_style' => '',
  273. 'description' => 1,
  274. 'description_position' => 'bottom',
  275. 'image_link' => 'none',
  276. ),
  277. ),
  278. );
  279. if (module_exists('colorbox')) {
  280. $info['video_embed_field_thumbnail_colorbox'] = array(
  281. 'label' => t('Thumbnail Preview w/Colorbox'),
  282. 'field types' => array('video_embed_field'),
  283. 'settings' => array(
  284. 'video_style' => 'normal',
  285. 'image_style' => '',
  286. 'description' => 1,
  287. 'description_position' => 'bottom',
  288. ),
  289. );
  290. $info['video_embed_field_url_colorbox'] = array(
  291. 'label' => t('URL to Video w/Colorbox'),
  292. 'field types' => array('video_embed_field'),
  293. 'settings' => array(
  294. 'video_style' => 'normal',
  295. ),
  296. );
  297. }
  298. return $info;
  299. }
  300. /**
  301. * Implements hook_field_formatter_settings_form().
  302. */
  303. function video_embed_field_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  304. $display = $instance['display'][$view_mode];
  305. $settings = $display['settings'];
  306. $element = array();
  307. if ($display['type'] == 'video_embed_field' || $display['type'] == 'video_embed_field_thumbnail_colorbox' || $display['type'] == 'video_embed_field_url_colorbox') {
  308. $video_styles = video_embed_field_video_style_options(FALSE);
  309. $element['video_style'] = array(
  310. '#title' => t('Video style'),
  311. '#type' => 'select',
  312. '#default_value' => $settings['video_style'],
  313. '#options' => $video_styles,
  314. );
  315. }
  316. if ($display['type'] == 'video_embed_field_thumbnail' || $display['type'] == 'video_embed_field_thumbnail_colorbox') {
  317. $element['image_style'] = array(
  318. '#title' => t('Image style'),
  319. '#type' => 'select',
  320. '#options' => image_style_options(FALSE),
  321. '#default_value' => $settings['image_style'],
  322. '#empty_option' => t('None (original image)'),
  323. );
  324. }
  325. if ($display['type'] == 'video_embed_field_thumbnail') {
  326. $link_types = array(
  327. 'content' => t('Content'),
  328. 'source' => t('Video Source'),
  329. );
  330. $element['image_link'] = array(
  331. '#title' => t('Link thumbnail to'),
  332. '#type' => 'select',
  333. '#default_value' => $settings['image_link'],
  334. '#empty_option' => t('Nothing'),
  335. '#options' => $link_types,
  336. );
  337. }
  338. if ($instance['settings']['description_field'] && $display['type'] != 'video_embed_field_url' && $display['type'] != 'video_embed_field_url_colorbox') {
  339. $element['description'] = array(
  340. '#title' => t('Show description'),
  341. '#type' => 'checkbox',
  342. '#default_value' => $settings['description'],
  343. );
  344. $element['description_position'] = array(
  345. '#title' => t('Description Position'),
  346. '#type' => 'select',
  347. '#options' => array(
  348. 'top' => t('Top'),
  349. 'bottom' => t('Bottom'),
  350. ),
  351. '#default_value' => $settings['description_position'],
  352. '#states' => array(
  353. 'visible' => array(
  354. ':input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][description]"]' => array('checked' => TRUE),
  355. ),
  356. ),
  357. );
  358. }
  359. return $element;
  360. }
  361. /**
  362. * Implements hook_field_formatter_settings_summary().
  363. */
  364. function video_embed_field_field_formatter_settings_summary($field, $instance, $view_mode) {
  365. $display = $instance['display'][$view_mode];
  366. $settings = $display['settings'];
  367. $summary = array();
  368. if ($display['type'] == 'video_embed_field' || $display['type'] == 'video_embed_field_thumbnail_colorbox' || $display['type'] == 'video_embed_field_url_colorbox') {
  369. $video_styles = video_embed_field_video_style_options(FALSE);
  370. // Styles could be lost because of enabled/disabled modules that defines
  371. // their styles in code.
  372. if (isset($video_styles[$settings['video_style']])) {
  373. $summary[] = t('Video style: @style', array('@style' => $video_styles[$settings['video_style']]));
  374. }
  375. }
  376. if ($display['type'] == 'video_embed_field_thumbnail' || $display['type'] == 'video_embed_field_thumbnail_colorbox') {
  377. $image_styles = image_style_options(FALSE);
  378. if (isset($image_styles[$settings['image_style']])) {
  379. $summary[] = t('Image style: @style', array('@style' => $image_styles[$settings['image_style']]));
  380. }
  381. // No Image style (original image).
  382. else {
  383. $summary[] = t('Original Image.');
  384. }
  385. if (isset($settings['image_link'])) {
  386. $summary[] = t('Image link: @image_link', array('@image_link' => $settings['image_link']));
  387. }
  388. else {
  389. $summary[] = t('Image link: none');
  390. }
  391. }
  392. if (isset($settings['description'])) {
  393. if ($settings['description'] && $instance['settings']['description_field']) {
  394. $summary[] = t('Show description');
  395. }
  396. elseif ($instance['settings']['description_field']) {
  397. $summary[] = t('Hide description');
  398. }
  399. }
  400. return implode('<br />', $summary);
  401. }
  402. /**
  403. * Implements hook_field_formatter_view().
  404. */
  405. function video_embed_field_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  406. $element = array();
  407. $settings = $display['settings'];
  408. if ($display['type'] == 'video_embed_field_thumbnail' && $display['settings']['image_link'] == 'content') {
  409. $path = entity_uri($entity_type, $entity);
  410. }
  411. foreach ($items as $delta => $item) {
  412. // Create the render array for the description.
  413. if (isset($item['description']) && $item['description'] && $settings['description'] && $instance['settings']['description_field']) {
  414. $description = array(
  415. '#prefix' => '<div class="video-embed-description">',
  416. '#markup' => check_plain($item['description']),
  417. '#suffix' => '</div>',
  418. );
  419. $alt = $item['description'];
  420. }
  421. else {
  422. $description = array();
  423. $alt = '';
  424. }
  425. // Render the field.
  426. if ($display['type'] == 'video_embed_field') {
  427. $element[$delta] = array(
  428. array(
  429. '#theme' => 'video_embed_field_embed_code',
  430. '#url' => $item['video_url'],
  431. '#style' => $settings['video_style'],
  432. '#video_data' => !empty($item['video_data']) ? unserialize($item['video_data']) : array(),
  433. ),
  434. );
  435. }
  436. elseif ($display['type'] == 'video_embed_field_url') {
  437. $element[$delta] = array(
  438. array(
  439. '#markup' => url($item['video_url']),
  440. ),
  441. );
  442. }
  443. elseif ($display['type'] == 'video_embed_field_thumbnail') {
  444. if (isset($item['thumbnail_path'])) {
  445. if ($display['settings']['image_link'] == 'source') {
  446. if ($ret = parse_url($item['video_url'])) {
  447. if (!isset($ret["scheme"])) {
  448. $item['video_url'] = "http://{$item['video_url']}";
  449. }
  450. }
  451. $path = array(
  452. 'path' => $item['video_url'],
  453. 'options' => array(),
  454. );
  455. }
  456. $element[$delta] = array(
  457. '#theme' => 'image_formatter',
  458. '#item' => array('uri' => $item['thumbnail_path'], 'alt' => $alt),
  459. '#image_style' => $display['settings']['image_style'],
  460. '#path' => isset($path) ? $path : '',
  461. );
  462. }
  463. // Incase no thumbnail was downloaded/provider doesn't support thumbnails.
  464. else {
  465. $element[$delta] = array();
  466. }
  467. }
  468. elseif ($display['type'] == 'video_embed_field_thumbnail_colorbox') {
  469. if (isset($item['thumbnail_path'])) {
  470. if ($ret = parse_url($item['video_url'])) {
  471. if (!isset($ret["scheme"])) {
  472. $item['video_url'] = "http://{$item['video_url']}";
  473. }
  474. }
  475. $element[$delta] = array(
  476. array(
  477. '#theme' => 'video_embed_field_colorbox_code',
  478. '#image_url' => $item['thumbnail_path'],
  479. '#image_style' => $display['settings']['image_style'],
  480. '#image_alt' => $alt,
  481. '#video_url' => $item['video_url'],
  482. '#video_style' => $display['settings']['video_style'],
  483. '#video_data' => unserialize($item['video_data']),
  484. ),
  485. );
  486. }
  487. // Incase no thumbnail was downloaded/provider doesn't support thumbnails.
  488. else {
  489. $element[$delta] = array();
  490. }
  491. }
  492. elseif ($display['type'] == 'video_embed_field_url_colorbox') {
  493. $path = video_embed_field_get_ajax_url($item['video_url'], $display['settings']['video_style']);
  494. $element[$delta] = array(
  495. array(
  496. '#markup' => url($path['path'], $path['options']),
  497. ),
  498. );
  499. }
  500. // Get the HTML instead of the array, because we append it to the suffix.
  501. // This way, the thumbnail link doesn't make the description a link as well.
  502. $description_html = drupal_render($description);
  503. $pos = isset($settings['description_position']) ? $settings['description_position'] : 'bottom';
  504. if ($pos == 'top') {
  505. $element[$delta]['#prefix'] = isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : '';
  506. $element[$delta]['#prefix'] = $description_html . $element[$delta]['#prefix'];
  507. }
  508. else {
  509. $element[$delta]['#suffix'] = isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '';
  510. $element[$delta]['#suffix'] .= $description_html;
  511. }
  512. }
  513. return $element;
  514. }