/[drupal]/contributions/modules/video_upload/video_upload.module
ViewVC logotype

Contents of /contributions/modules/video_upload/video_upload.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.23 - (show annotations) (download) (as text)
Sun Oct 11 22:06:52 2009 UTC (6 weeks, 3 days ago) by jhedstrom
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-7--1
Changes since 1.22: +60 -140 lines
File MIME type: text/x-php
Initital 7.x port.
1 <?php
2
3 // $Id: video_upload.module,v 1.14.2.9 2009/09/04 20:51:16 jhedstrom Exp $
4
5 /**
6 * @file
7 * video upload module
8 * @todo
9 * See TODO.txt, and inline todo comments
10 */
11
12 // Load all Field module hooks for Video Upload.
13 module_load_include('inc', 'video_upload', 'video_upload.field');
14
15 /**
16 * Video status levels.
17 */
18 define('VIDEO_UPLOAD_STATUS_ORPHANED', 'orphaned');
19 define('VIDEO_UPLOAD_STATUS_DELETE', 'delete');
20 define('VIDEO_UPLOAD_STATUS_BAD', 'bad');
21 define('VIDEO_UPLOAD_STATUS_UNKNOWN', 'unknown');
22 define('VIDEO_UPLOAD_STATUS_OK', 'ok');
23 define('VIDEO_UPLOAD_STATUS_OK_SYNCED', 'synced');
24 define('VIDEO_UPLOAD_STATUS_UPLOAD_PENDING', 'upload_pending');
25
26 /**
27 * Video synchronization.
28 */
29 define('VIDEO_UPLOAD_SYNC_NONE', 0);
30 define('VIDEO_UPLOAD_SYNC', 1);
31 define('VIDEO_UPLOAD_SYNC_APPEND', 2);
32
33 /**
34 * Implement hook_init().
35 */
36 function video_upload_init() {
37 module_load_include('inc', 'video_upload', 'video_upload_widget');
38 }
39
40 /**
41 * Initialize the Video Upload provider.
42 */
43 function video_upload_initialize_provider() {
44 // @TODO
45 // Providers should be configurable (only applicable once there is more
46 // than one provider though).
47 require_once drupal_get_path('module', 'video_upload') . '/providers/youtube/youtube.inc';
48 }
49
50 /**
51 * Implement hook_theme().
52 */
53 function video_upload_theme() {
54 $theme = array(
55 'video_upload_video' => array(
56 'arguments' => array('yt_id' => NULL, 'width' => '425', 'height' => '355', 'field' => array(), 'params' => array(), 'attributes' => array()),
57 ),
58 'video_upload_video_thumb' => array(
59 'arguments' => array('field' => NULL, 'item' => NULL, 'node' => NULL, 'as_link' => FALSE),
60 ),
61 'video_upload_video_status_message' => array(
62 'arguments' => array('item' => NULL, 'message' => NULL),
63 ),
64 'video_upload_admin_video_form' => array(
65 'arguments' => array('form' => NULL),
66 ),
67 'video_upload_status_text' => array(
68 'arguments' => array('status' => NULL),
69 ),
70 'video_upload_missing_image' => array(
71 'arguments' => array('style' => 'full', 'width' => 425, 'height' => 355, 'attributes' => array()),
72 ),
73
74 // video_upload_widget form element type theme function.
75 'video_upload_widget' => array(
76 'arguments' => array('element' => NULL),
77 'file' => 'video_upload_widget.inc',
78 ),
79 'video_upload_widget_preview' => array(
80 'arguments' => array('item' => NULL),
81 'file' => 'video_upload_widget.inc',
82 ),
83 );
84
85 // CCK formatters.
86 $formatters = array(
87 'video_upload_formatter_default',
88 'video_upload_formatter_thumb',
89 'video_upload_formatter_thumb_link',
90 'video_upload_formatter_small',
91 );
92
93 foreach ($formatters as $formatter) {
94 $theme[$formatter] = array(
95 'arguments' => array('element' => NULL),
96 );
97 }
98
99 foreach ($theme as $function => $data) {
100 if (!isset($theme[$function]['file'])) {
101 $theme[$function]['file'] = 'video_upload.theme.inc';
102 }
103 }
104
105 return $theme;
106 }
107
108 /**
109 * Implement hook_permission().
110 */
111 function video_upload_permission() {
112 return array(
113 'administer video upload settings' => array(
114 'title' => t('Administer video upload settings'),
115 'description' => t('Access and change video upload account credentials for 3rd-party video.'),
116 ),
117 'administer uploaded videos' => array(
118 'title' => t('Administer uploaded videos'),
119 'description' => t('Manage videos uploaded to 3rd-party video provider.'),
120 ),
121 );
122 }
123
124 /**
125 * Implement hook_menu().
126 */
127 function video_upload_menu() {
128 $items['admin/config/media/video-upload'] = array(
129 'title' => 'Video Upload Settings',
130 'page callback' => 'drupal_get_form',
131 'page arguments' => array('_video_upload_admin_settings_form'),
132 'access arguments' => array('administer video upload settings'),
133 'file' => 'video_upload.admin.inc',
134 'description' => t('Video provider settings for the <em>Video Upload</em> module.'),
135 );
136
137 // The js callback that the provider redirects to.
138 $items['video-upload/js'] = array(
139 'title' => 'Video upload js callback',
140 'page callback' => 'video_upload_js',
141 'access arguments' => array('access content'),
142 'type' => MENU_CALLBACK,
143 'file' => 'video_upload.pages.inc',
144 );
145
146 // Admin page for removing stranded videos (not attached to a node).
147 $items['admin/content/video-upload'] = array(
148 'title' => 'Manage Video Uploads',
149 'page callback' => 'video_upload_admin_video',
150 'access arguments' => array('administer uploaded videos'),
151 'file' => 'video_upload.admin.inc',
152 'description' => t('Manage all uploaded videos.'),
153 );
154
155 return $items;
156 }
157
158 /**
159 * Implement hook_elements().
160 */
161 function video_upload_elements() {
162 $elements = array();
163
164 // Uses filefield as a starting point, and adds additional processing.
165 $filefield_elements = filefield_elements();
166
167 // Unset FileField's validate callback since it will fail to
168 // validate as FileField knows nothing of this file.
169 $filefield_elements['filefield_widget']['#element_validate'] = array();
170
171 $elements['video_upload_widget'] = $filefield_elements['filefield_widget'];
172 $elements['video_upload_widget']['#process'][] = 'video_upload_widget_process';
173 $elements['video_upload_widget']['#element_validate'][] = 'video_upload_widget_validate';
174
175 // Video upload contains additional file meta-data, so requires a separate
176 // value callback.
177 $elements['video_upload_widget']['#value_callback'] = 'video_upload_widget_value';
178
179 return $elements;
180 }
181
182 /**
183 * Implement hook_file_references().
184 */
185 function video_upload_file_references($file) {
186 $count = video_upload_get_file_reference_count($file);
187 return $count ? array('video_upload' => $count) : NULL;
188 }
189
190 /**
191 * Count the number of times the file is referenced within a field.
192 *
193 * @param $file
194 * A file object.
195 * @param $field
196 * Optional. The CCK field array or field name as a string.
197 * @return
198 * An integer value.
199 */
200 function video_upload_get_file_reference_count($file, $field = NULL) {
201 $fields = video_upload_get_field_list(NULL, $field);
202 $file = (object) $file;
203
204 $references = 0;
205 foreach ($fields as $field) {
206 $db_info = content_database_info($field);
207 $references += db_result(db_query(
208 'SELECT count('. $db_info['columns']['fid']['column'] .')
209 FROM {'. $db_info['table'] .'}
210 WHERE '. $db_info['columns']['fid']['column'] .' = %d', $file->fid
211 ));
212
213 // If a field_name is present in the file object, the file is being deleted
214 // from this field.
215 if (isset($file->field_name) && $field['field_name'] == $file->field_name) {
216 // If deleting the entire node, count how many references to decrement.
217 if (isset($file->delete_nid)) {
218 $node_references = db_result(db_query(
219 'SELECT count('. $db_info['columns']['fid']['column'] .')
220 FROM {'. $db_info['table'] .'}
221 WHERE '. $db_info['columns']['fid']['column'] .' = %d AND nid = %d', $file->fid, $file->delete_nid
222 ));
223 $references = $references - $node_references;
224 }
225 else {
226 $references = $references - 1;
227 }
228 }
229 }
230
231 return $references;
232 }
233
234 /**
235 * Return an array of file fields within a node type or by field name.
236 *
237 * @param $field
238 * Optional. May be either a field array or a field name.
239 * @param $node_type
240 * Optional. The node type to filter the list of fields.
241 */
242 function video_upload_get_field_list($node_type = NULL, $field = NULL) {
243 // Build the list of fields to be used for retrieval.
244 if (isset($field)) {
245 if (is_string($field)) {
246 $field = content_fields($field, $node_type);
247 }
248 $fields = array($field['field_name'] => $field);
249 }
250 elseif (isset($node_type)) {
251 $type = content_types($node_type);
252 $fields = $type['fields'];
253 }
254 else {
255 $fields = content_fields();
256 }
257
258 // Filter down the list just to file fields.
259 foreach ($fields as $key => $field) {
260 if ($field['type'] != 'video_upload') {
261 unset($fields[$key]);
262 }
263 }
264
265 return $fields;
266 }
267
268 /**
269 * Implement hook_field_widget_info().
270 */
271 function video_upload_field_widget_info() {
272 $file = module_invoke('file', 'field_widget_info');
273 $video = array(
274 'video_upload_widget' => array(
275 'label' => t('Upload/Edit/Display Video'),
276 'description' => t('Upload video files to a 3rd-party provider.'),
277 'field types' => array('video_upload'),
278 'behaviors' => array(
279 'multiple values' => FIELD_BEHAVIOR_DEFAULT,
280 'default value' => FIELD_BEHAVIOR_DEFAULT,
281 ),
282 ),
283 );
284 $video['video_upload_widget']['settings'] = $file['file_generic']['settings'];
285 $video['video_upload_widget']['settings'] += array(
286 'video_category' => '',
287 'auto_delete_rejected_videos' => 0,
288 'remove_deleted_videos' => 0,
289 'default_title' => '',
290 'default_description' => '',
291 'default_keywords' => '',
292 'developer_tags' => '',
293 'display' => array(
294 'autoplay' => 0,
295 'default_width' => 480,
296 'default_height' => 295,
297 'small_width' => 240,
298 'small_height' => 148,
299 'thumb_width' => 128,
300 'thumb_height' => 72,
301 'related_videos' => 0,
302 'fullscreen' => 1,
303 ),
304 'default_title_sync',
305 'default_description_sync',
306 'default_keyword_sync',
307 );
308 return $video;
309 }
310
311 /**
312 * Implement hook_widget().
313 */
314 function video_upload_widget(&$form, &$form_state, $field, $items, $delta = 0) {
315 if ($field['widget']['use_browser_upload_method']) {
316 // The browser upload method is sufficiently different from direct upload
317 // that it warrants entirely separate logic.
318 // @todo
319 module_load_include('browser.inc', 'video_upload');
320 return _video_upload_browser_method_widget($form, $form_state, $field, $items, $delta);
321 }
322
323 if (empty($items[$delta])) {
324 $items[$delta] = array(
325 'video_id' => '',
326 'video_status' => VIDEO_UPLOAD_STATUS_UPLOAD_PENDING,
327 'video_status_ts' => $_SERVER['REQUEST_TIME'],
328 );
329 }
330 $element = filefield_widget($form, $form_state, $field, $items, $delta);
331
332 return $element;
333 }
334
335 /**
336 * Implement CCK's hook_content_is_empty().
337 */
338 function video_upload_content_is_empty($item, $field) {
339 // Use FileField's definition of empty.
340 return filefield_content_is_empty($item, $field);
341 }
342
343 /**
344 * Sets a default title for uploaded video.
345 */
346 function _video_upload_set_default_title($node, $widget) {
347 $title = '';
348 switch ($widget['default_title_sync']) {
349 case VIDEO_UPLOAD_SYNC_APPEND :
350 $title = $widget['default_title'];
351 if ($node->title) {
352 $title .= ': ';
353 }
354 // Fall through to append.
355 case VIDEO_UPLOAD_SYNC :
356 if ($node->title) {
357 $title = $title . $node->title;
358 break;
359 }
360 case VIDEO_UPLOAD_SYNC_NONE :
361 default :
362 $title = $widget['default_title']
363 ? $widget['default_title']
364 : t('Video from @site_name', array('@site_name' => variable_get('site_name', 'Drupal')));
365 }
366
367 if (module_exists('token')) {
368 global $user;
369 $title = token_replace($title);
370 $title = token_replace($title, 'user', $user);
371 $title = token_replace($title, 'node', $node);
372 }
373
374 // Can't be blank.
375 if (!trim($title)) {
376 $title = t('Placeholder Title');
377 }
378
379 $max = _video_upload_max_length_provider('title');
380 $title = substr($title, 0, $max);
381 return $title;
382 }
383
384 /**
385 * Sets a default description for uploaded video.
386 * @TODO: site admins need to have more control over this (eg, some may
387 * prefer that the site description goes up with the video, rather than
388 * user-entered data.
389 */
390 function _video_upload_set_default_description($node, $widget) {
391 // Set description to teaser.
392 switch ($widget['default_description_sync']) {
393 case VIDEO_UPLOAD_SYNC_APPEND :
394 $description = $widget['default_description'] . "\n\n";
395 // Aall through to add teaser.
396 case VIDEO_UPLOAD_SYNC :
397 if ($node->teaser) {
398 $description = $description . $node->teaser;
399 break;
400 }
401 // Otherwise, fall through.
402 case VIDEO_UPLOAD_SYNC_NONE :
403 $description = $widget['default_description'];
404
405 }
406
407 if (module_exists('token')) {
408 global $user;
409 $description = token_replace($description);
410 $description = token_replace($description, 'user', $user);
411 $description = token_replace($description, 'node', $node);
412 }
413
414 if (!trim($description)) {
415 $description = t('Video uploaded from @site_name : @site_slogan', array('@site_name' => variable_get('site_name', 'Drupal'), '@site_slogan' => variable_get('site_slogan', FALSE)));
416
417 if (module_exists('token')) {
418 global $user;
419 $description = token_replace($description, 'user', $user);
420 }
421 }
422
423 // No tags allowed.
424 // @TODO This may be YouTube specific.
425 return strip_tags($description);
426 }
427
428 /**
429 * Sets developer tags.
430 * @return array
431 */
432 function _video_upload_set_developer_tags($node, $widget) {
433 if ($widget['developer_tags']) {
434 $tags = explode(',', $widget['developer_tags']);
435 }
436 else {
437 return array(substr(str_replace(array(',', ' '), '', trim(variable_get('site_name', 'Drupal'))), 0, 25));
438 }
439
440 if (module_exists('token')) {
441 global $user;
442 foreach ($tags as $key => $tag) {
443 // There seems to be an invisible 26 character limit.
444 // @TODO This is YouTube specific.
445 $tags[$key] = substr(str_replace(array(',', ' '), '', trim(check_plain(token_replace($tag, 'user', $user)))), 0, 25);
446 }
447 }
448
449 return $tags;
450 }
451
452 /**
453 * Implement hook_cron().
454 */
455 function video_upload_cron() {
456 module_load_include('admin.inc', 'video_upload');
457
458 // Find types containing a video_upload field.
459 $fields = _video_upload_relevant_fields();
460
461 // Verify videos.
462 _video_upload_verify_all($fields);
463
464 // Delete videos queued for deletion.
465 _video_upload_delete_rejected_videos($fields);
466
467 // Update provider info for all flagged videos.
468 _video_upload_update_all_videos($fields);
469
470 // Upload any pending videos.
471 _video_upload_upload_all($fields);
472 }
473
474 /**
475 * Implement hook_views_api().
476 */
477 function video_upload_views_api() {
478 return array(
479 'api' => 2,
480 'path' => drupal_get_path('module', 'video_upload') . '/views',
481 );
482 }
483
484 /**
485 * Implement hook_field_settings_alter().
486 *
487 * For any fields using the video upload widget:
488 * - Adds required database columns.
489 * - Defines views data.
490 */
491 function video_upload_field_settings_alter(&$data, $op, $field) {
492 if (!isset($field['widget']) || $field['widget']['type'] != 'video_upload_widget') {
493 return;
494 }
495 switch ($op) {
496 case 'database columns':
497 $data += array(
498 // The provider ID.
499 'video_id' => array(
500 'type' => 'varchar',
501 'length' => 32,
502 'views' => TRUE,
503 ),
504 // Video status.
505 'video_status' => array(
506 'type' => 'varchar',
507 'length' => 32,
508 'default' => VIDEO_UPLOAD_STATUS_UPLOAD_PENDING,
509 'sortable' => TRUE,
510 'views' => TRUE,
511 ),
512 // Time of status update.
513 'video_status_ts' => array(
514 'type' => 'int',
515 'length' => 11,
516 'sortable' => TRUE,
517 'default' => '0',
518 'views' => TRUE,
519 ),
520 );
521 break;
522
523 case 'views data':
524 $table_alias = content_views_tablename($field);
525 $field_name = $field['field_name'];
526 $data[$table_alias][$field_name . '_video_status']['filter']['handler'] = 'views_handler_filter_video_upload_status';
527 $data[$table_alias][$field_name . '_video_status_ts']['filter']['handler'] = 'views_handler_filter_date';
528 break;
529 }
530 }
531
532 /**
533 * Get taxonomy terms associated with node.
534 * @param object $node
535 * @return array
536 * Array of keywords.
537 */
538 function _video_upload_get_formatted_taxonomy($node) {
539 $video_taxonomy = array();
540
541 if (!$node->taxonomy) {
542 return FALSE;
543 }
544
545 foreach ($node->taxonomy as $tid => $term) {
546 $video_taxonomy[] = $term->name;
547 }
548
549 if (empty($video_taxonomy)) {
550 return FALSE;
551 }
552
553 return $video_taxonomy;
554 }
555
556 /**
557 * Obtain the value of various maximum lengths.
558 */
559 function _video_upload_max_length_provider($entity = 'title') {
560 // @TODO Abstract this out (60 is the yt max).
561 return 60;
562 }
563
564 /**
565 * Prepare a node and video to be sent to the configured provider. Also sets
566 * the node status to unknown since once the video is sent, the status is
567 * unknown until processing is complete.
568 *
569 * @param object $video
570 * A local video object.
571 * @return boolean
572 * True if any videos were uploaded.
573 */
574 function video_upload_upload($field, $video) {
575 $node = node_load($video->nid);
576 // Attach file information.
577 $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE fid = %d", array(':fid' => $video->fid)));
578 $video->filepath = $file->filepath;
579 $video->filemime = $file->filemime;
580 $result = video_upload_provider_upload($video, $node, $field);
581 if ($result['video_id']) {
582 $video->video_id = $result['video_id'];
583 $video->video_status = VIDEO_UPLOAD_STATUS_UNKNOWN;
584 $video->video_status_ts = $_SERVER['REQUEST_TIME'];
585 $update = TRUE;
586 }
587
588 return _video_upload_update_video($video);
589 }
590
591 /**
592 * Call the provider's upload function and send the video.
593 *
594 * @param $node
595 * The associated video.
596 * @param $video
597 * The filefield video array.
598 */
599 function video_upload_provider_upload($video, $node, $field) {
600 // @todo this needs to be abstracted away from youtube.
601 video_upload_initialize_provider();
602 return video_upload_upload_youtube($video, $node, $field);
603 }
604
605 /**
606 * Connect to the provider.
607 * @param mixed $http_client
608 * object http_client. If passed as boolean TRUE, the http_client will be
609 * generated.
610 * @return video provider connection object
611 */
612 function video_upload_connect($http_client) {
613 if ($http_client === TRUE) {
614 $http_client = video_upload_authenticate();
615 }
616 // @todo abstract out youtube
617 video_upload_initialize_provider();
618 return _video_upload_youtube($http_client);
619 }
620
621 /**
622 * Authenticate to the provider.
623 */
624 function video_upload_authenticate($reauthenticate = FALSE) {
625 static $authentication;
626 if (!$authentication || $reauthenticate) {
627 // @todo abstract out youtube
628 video_upload_initialize_provider();
629 $authentication = _video_upload_authenticate_youtube();
630 }
631 return $authentication;
632 }
633
634 /**
635 * Remove a video from the local database.
636 */
637 function video_upload_delete_local($video) {
638 if ($video->fid) {
639 return db_query("DELETE FROM {video_upload} WHERE fid = %d", array(':fid' => $video->fid));
640 }
641 watchdog('video_upload', 'Attempted to delete a video without a fid.', array(), WATCHDOG_ERROR);
642 }
643
644 /**
645 * Get available video statuses.
646 */
647 function video_upload_get_all_statuses() {
648 return array(
649 VIDEO_UPLOAD_STATUS_ORPHANED => t('Orphaned'),
650 VIDEO_UPLOAD_STATUS_DELETE => t('Queued for deletion'),
651 VIDEO_UPLOAD_STATUS_BAD => t('Bad'),
652 VIDEO_UPLOAD_STATUS_UNKNOWN => t('Unknown'),
653 VIDEO_UPLOAD_STATUS_OK => t('Good'),
654 VIDEO_UPLOAD_STATUS_OK_SYNCED => t('Good: Synced to provider'),
655 VIDEO_UPLOAD_STATUS_UPLOAD_PENDING => t('Upload pending'),
656 );
657 }
658
659 /**
660 * Update a video upload record.
661 */
662 function _video_upload_update_video($video) {
663 $node = node_load($video->nid);
664 $field = $video->field;
665 $field_name = $video->field['field_name'];
666 $delta = isset($video->delta) ? $video->delta : 1;
667 $node->{$field_name}[$delta - 1]['video_status_ts'] = $_SERVER['REQUEST_TIME'];
668 $node->{$field_name}[$delta - 1]['video_status'] = $video->video_status;
669 $node->{$field_name}[$delta - 1]['video_id'] = $video->video_id;
670 node_save($node);
671 return $video->video_id;
672 }

  ViewVC Help
Powered by ViewVC 1.1.2