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

Contents of /contributions/modules/video/video.module

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


Revision 1.70 - (show annotations) (download) (as text)
Wed May 27 01:21:03 2009 UTC (6 months ago) by heshanmw
Branch: MAIN
CVS Tags: HEAD
Changes since 1.69: +74 -55 lines
File MIME type: text/x-php
updating head
1 <?php
2 //$Id$
3 /**
4 * @file video.module
5 *
6 * @author Heshan Wanigasooriya <heshan at heidisoft dot com>
7 * <heshanmw at gmail dot com>
8 * @todo
9 */
10 /**
11 * Let's include views logic if views module is enabled
12 */
13 if (module_exists('views')) {
14 module_load_include('inc', 'video', 'views_video');
15 }
16
17 /********************************************************************
18 * General Hooks
19 ********************************************************************/
20
21 /**
22 * Help hook
23 * Implementation of hook_help
24 * @param $section
25 * string of the area of Drupal where help was requested
26 *
27 * @return
28 * string of help information
29 */
30
31 function video_help($path, $arg) {
32 switch ($path) {
33 case 'admin/help#video':
34 $output = '<p>'. t('The Video Module is used to create and administrator Video nodes for Drupal') .'</p>';
35 return $output;
36 }
37 }
38
39 /**
40 * Implementation of hook_menu().
41 *
42 * @param $may_cache
43 * boolean indicating whether cacheable menu items should be returned
44 *
45 * @return
46 * array of menu information
47 */
48 function video_menu() {
49 global $user;
50 $items = array();
51
52 $items['video'] = array(
53 'title' => 'videos',
54 'page callback' => 'drupal_get_form',
55 'page arguments' => array('video_page'),
56 'access arguments' => array('access video'),
57 'type' => MENU_SUGGESTED_ITEM);
58
59 $items['video/feed'] = array(
60 'title' => 'videos feed',
61 'page callback' => 'drupal_get_form',
62 'page arguments' => array('video_feed'),
63 'access arguments' => array('access video'),
64 'type' => MENU_CALLBACK);
65
66
67 $items["node/add/video"] = array(
68 'title' => 'Video',
69 'description' => 'Allow a variety of video formats to be posted as nodes in your site',
70 'page callback' => 'video_add',
71 'access arguments' => array('create video'));
72
73 $items['admin/settings/video'] = array(
74 'title' => 'Video',
75 'description' => 'Configure different aspects of the video module and its plugins',
76 'page callback' => 'drupal_get_form',
77 'page arguments' => array('video_settings_form'),
78 'access arguments' => array('administer video'),
79 'type' => MENU_NORMAL_ITEM,
80 );
81
82 if (arg(0) == 'node' && is_numeric(arg(1))) {
83 if ($node = node_load(arg(1)) and $node->type == 'video') {
84
85 //enable the download tab only if it is supported
86 if (video_support_download($node)) {
87
88 $menu_type = (variable_get('video_displaydownloadmenutab', 1)) ? MENU_LOCAL_TASK : MENU_CALLBACK;
89 $items['node/'.$node->nid.'/download'] = array(
90 'title' => 'Download',
91 'page callback' => 'video_download',
92 'page arguments' => array($node),
93 'access arguments' => array('access video') && node_access('view', $node, $user->uid),
94 'weight' => 5,
95 'type' => $menu_type);
96 }
97 }
98 }
99 return $items;
100 }
101
102
103 /**
104 * Internal Drupal links hook
105 *
106 * @param $type
107 * string type of link to show
108 *
109 * @param $node
110 * object of node information
111 *
112 * @return
113 * array of link information
114 */
115 function video_link($type, $node = NULL) {
116 $link = array();
117
118 // Node links for a video
119 if ($type == 'node' && $node->type == 'video' && $node->vidfile && user_access('access video')) {
120 //If the video is of type youtube and multi-file downloads aren't turned on don't show the download link.
121 if (!video_support_download($node) || $node->disable_multidownload == 1) {
122 $display_download_link = 0;
123 }
124 else {
125 $display_download_link = variable_get('video_displaydownloadlink', 1);
126 }
127
128 if ($display_download_link == 1) {
129 $link['video_download'] = array(
130 'title' => t('download'),
131 'href' => "node/$node->nid/download",
132 'attributes' => array(
133 'class' => 'outgoing',
134 'title' => t('download @link', array('@link' => $node->title)),
135 ),
136 );
137 }
138 if (variable_get('video_displayplaytime', 1) && $node->playtime_seconds > 0) { // hide the duration if the admin hided it or we don't have playtime informations
139 $link['playtime'] = array(
140 'title' => format_interval($node->playtime_seconds),
141 );
142 }
143 if (variable_get('video_displayfilesize', 1) && $node->size != 0) {
144 $link['size'] = array(
145 'title' => format_size($node->size),
146 );
147 }
148 if (variable_get('video_playcounter', 1) && user_access('view play counter')) {
149 $link['play_counter'] = array(
150 'title' => format_plural($node->play_counter, '1 play', '@count plays'),
151 );
152 }
153 if (variable_get('video_downloadcounter', 1) && user_access('view download counter') && video_support_download($node)) {
154 $link['download_counter'] = array(
155 'title' => format_plural($node->download_counter, '1 download', '@count downloads'),
156 );
157 }
158
159 return $link;
160 }
161 return array();
162 }
163
164
165 /**
166 * Displays a Drupal page containing recently added videos
167 *
168 * @return
169 * string HTML output
170 */
171 function video_page() {
172 $output = '';
173 if (arg(1) != 'help') { //We are not reading help so output a list of recent video nodes.
174 $result = pager_query(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE n.type = 'video' AND n.status = 1 ORDER BY n.created DESC"), variable_get('default_nodes_main', 10));
175 while ($node = db_fetch_object($result)) {
176 $output .= node_view(node_load($node->nid), 1);
177 }
178 $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
179 // adds feed icon and link
180 drupal_add_link(array('rel' => 'alternate',
181 'type' => 'application/rss+xml',
182 'title' => variable_get('site_name', 'drupal') . ' ' . t('videos'),
183 'href' => url('video/feed/')));
184
185 $output .= '<br />' . theme('feed_icon', url('video/feed'));
186 }
187 return $output;
188 }
189
190 /**
191 * Generate an RSS feed for videos
192 *
193 * @return
194 * feed
195 */
196 function video_feed() {
197 $channel = array(
198 'title' => variable_get('site_name', 'drupal') . ' ' . t('videos'),
199 'description' => t('Latest videos on') . ' ' . variable_get('site_name', 'drupal'),
200 'link' => url('video', array('absolute' => TRUE))
201 );
202
203 $result = db_query('SELECT n.nid FROM {node} n WHERE n.type = "video" AND n.status = 1 ORDER BY n.created DESC');
204 node_feed($result, $channel);
205 }
206
207 /**
208 * Permissions hook
209 *
210 * @return
211 * array of permissions
212 */
213 function video_perm() {
214 $array = array('create video', 'access video', 'administer video', 'play video', 'download video', 'view play counter', 'view download counter', 'edit own video', 'edit all video nodes');
215 return $array;
216 }
217
218 /**
219 * Settings Hook
220 *
221 * @return
222 * string of form content or error message
223 */
224 function video_settings_form() {
225 global $base_url;
226
227 $form = array();
228
229 $form['menu'] = array(
230 '#type' => 'fieldset',
231 '#title' => t('General behavior'),
232 '#collapsible' => TRUE,
233 '#collapsed' => TRUE
234 );
235
236 $vtypes = video_get_types_infos();
237
238 if ($vtypes) { // no vtype available
239 $video_types = array();
240 foreach ($vtypes as $vtype => $info) {
241 $video_types[$vtype] = $info['#name'];
242 }
243 $video_types[0] = t('No default type');
244 $form['menu']['video_default_video_type'] = array(
245 '#type' => 'select',
246 '#title' => t('Choose default video type'),
247 '#default_value' => variable_get('video_default_video_type', 0),
248 '#description' => t('For installations that have more than one video type available, this sets the default video type when a user visits node/add/video'),
249 '#options' => $video_types,
250 );
251 }
252
253 $form['menu']['video_displaydownloadmenutab'] = array(
254 '#type' => 'checkbox',
255 '#title' => t('Display download menu tab'),
256 '#default_value' => variable_get('video_displaydownloadmenutab', 1),
257 '#description' => t('Toggle display of menu tab to download video from the node page.')
258 );
259 $form['menu']['video_displaydownloadlink'] = array(
260 '#type' => 'checkbox',
261 '#title' => t('Display download link'),
262 '#default_value' => variable_get('video_displaydownloadlink', 1),
263 '#description' => t('Toggle display of "download" link (below the node content in most themes).')
264 );
265 $form['menu']['video_displayplaytime'] = array(
266 '#type' => 'checkbox',
267 '#title' => t('Display playtime'),
268 '#default_value' => variable_get('video_displayplaytime', 1),
269 '#description' => t('Toggle the display of the playtime for a video.')
270 );
271 $form['menu']['video_displayfilesize'] = array(
272 '#type' => 'checkbox',
273 '#title' => t('Display filesize'),
274 '#default_value' => variable_get('video_displayfilesize', 1),
275 '#description' => t('Toggle the display of the filesize for a video.')
276 );
277
278 $form['resolutions'] = array(
279 '#type' => 'fieldset',
280 '#title' => t('Video resolutions'),
281 '#collapsible' => TRUE,
282 '#collapsed' => TRUE
283 );
284
285 $form['resolutions']["video_resolution_width"] = array(
286 '#type' => 'textfield',
287 '#title' => t("Default width"),
288 '#default_value' => variable_get("video_resolution_width", 400),
289 '#description' => t('The width which will be used to scale video during playing. This let all videos on the website look the same')
290 );
291
292 $i = 1;
293 while($i <= 4) {
294 $form['resolutions']["video_resolution_{$i}_name"] = array(
295 '#type' => 'textfield',
296 '#title' => t("Resolution {$i} name"),
297 '#default_value' => variable_get("video_resolution_{$i}_name", ''),
298 );
299 $form['resolutions']["video_resolution_{$i}_value"] = array(
300 '#type' => 'textfield',
301 '#title' => t("Resolution {$i} value"),
302 '#default_value' => variable_get("video_resolution_{$i}_value", ''),
303 '#description' => t('The resolution: two numbers representing width and height separated by an "x"'),
304 );
305 $i++;
306 }
307
308 // statistics stuff
309 $form['counters'] = array(
310 '#type' => 'fieldset',
311 '#title' => t('Statistics counters'),
312 '#description' => t('To allow users to view counters visit: ') . l(t('access control'), 'admin/access'),
313 '#collapsible' => TRUE,
314 '#collapsed' => TRUE
315 );
316 $form['counters']['video_playcounter'] = array(
317 '#type' => 'checkbox',
318 '#title' => t('Count play hits'),
319 '#default_value' => variable_get('video_playcounter', 1),
320 '#description' => t('Counts a hit everytime someone views the play page.')
321 );
322 $form['counters']['video_downloadcounter'] = array(
323 '#type' => 'checkbox',
324 '#title' => t('Count downloads'),
325 '#default_value' => variable_get('video_downloadcounter', 1),
326 '#description' => t('Counts a hit everytime someone downloads a video.')
327 );
328
329 $form['flash'] = array(
330 '#type' => 'fieldset',
331 '#title' => t('Flash settings'),
332 '#collapsible' => TRUE,
333 '#collapsed' => TRUE
334 );
335 $form['flash']['video_flvplayerloader'] = array(
336 '#type' => 'textfield',
337 '#title' => t('Filename of Flash loader'),
338 '#default_value' => variable_get('video_flvplayerloader', 'FlowPlayer.swf'),
339 '#description' => t('The name of the Shockwave file that manages loading the FLV movie. This is relative to the website root.')
340 );
341 $form['ogg'] = array(
342 '#type' => 'fieldset',
343 '#title' => t('Ogg Theora settings'),
344 '#collapsible' => TRUE,
345 '#collapsed' => TRUE
346 );
347 $form['ogg']['video_cortado'] = array(
348 '#type' => 'textfield',
349 '#title' => t('Filename of Cortado Java Applet'),
350 '#default_value' => variable_get('video_cortado', $base_url . '/cortado.jar'),
351 '#description' => t('The path to the Cortado Applet to play Ogg Theora Files.')
352 );
353
354 return system_settings_form($form);
355 }
356
357
358 /**
359 * Form API callback to validate the upload settings form.
360 *
361 * Keeps the use from showing the play tab or the play link
362 * if they have chosen to display the video in the node body.
363 *
364 * @param $form_id
365 * The identifier of the form
366 *
367 * @param $form_values
368 * form values from the settings page
369 *
370 */
371 function video_settings_form_validate($form, &$form_state){
372 //print_r($form_state['values']); die;
373
374 // if admin set a name for a resolution he also have to set its value
375 while($i <= 4) {
376 if($form_state['values']["video_resolution_{$i}_name"] != '' && $form_state['values']["video_resolution_{$i}_value"] == '') {
377 form_set_error("video_resolution_{$i}_value", t('You have to set a value for resolution %res_num if you want to enable it.', array('%res_num' => $i)));
378 }
379 if($form_state['values']["video_resolution_{$i}_value"] != '' && !preg_match('/^[0-9]{2,4}x[0-9]{2,4}$/',$form_state['values']["video_resolution_{$i}_value"])) { // check valid resolution value
380 form_set_error("video_resolution_{$i}_value", t('You have to set valid value for resolution %res_num if you want to enable it. A valid value is 400x300', array('%res_num' => $i)));
381 }
382
383 $i++;
384 }
385 ; // for future use
386 }
387
388
389 /******************************************************************************
390 * Node Hooks
391 ******************************************************************************/
392
393 /**
394 * Implementation of _node_info().
395 *
396 * @return
397 * array
398 */
399 function video_node_info() {
400 return array('video' => array(
401 'name' => t('Video'),
402 'module' => 'video',
403 'description' => t('Allow a variety of video formats to be posted as nodes in your site'),
404 )
405 );
406 }
407
408 /**
409 * access hook
410 */
411 function video_access($op, $node, $account) {
412
413
414 if ($op == 'create') {
415 return user_access('create video', $account);
416 }
417
418 if ($op == 'update' || $op == 'delete') {
419 return (user_access('edit own video', $account) && ($account->uid == $node->uid)) || user_access('edit all video nodes', $account);
420 }
421 }
422
423 /**
424 * Implementation of hook_nodeapi().
425 * We use this to append <enclosure> tags to the RSS feeds Drupal generates.
426 */
427 function video_nodeapi($node, $op, $arg) {
428 switch ($op) {
429 case 'rss item':
430 if ($node->type == 'video') {
431 // RSS Enclosure http://cyber.law.harvard.edu/rss/rss.html#ltenclosuregtSubelementOfLtitemgt
432 $attributes['url'] = _video_get_fileurl($node->vidfile);
433 $attributes['length'] = $node->size;
434 $mime_type = _video_get_mime_type($node);
435 if ($mime_type) {
436 $attributes['type'] = $mime_type;
437 $enclosure = array('key' => 'enclosure', 'attributes' => $attributes);
438 }
439
440 // MRSS media:content http://search.yahoo.com/mrss
441 $media['url'] = $attributes['url'];
442 if ($attributes['length'] > 1) {
443 $media['fileSize'] = $attributes['length'];
444 }
445 if ($mime_type) {
446 $media['type'] = $mime_type;
447 }
448 if (isset($node->playtime_seconds) && $node->playtime_seconds > 0) {
449 $media['duration'] = $node->playtime_seconds;
450 }
451 if (isset($node->video_bitrate) && $node->video_bitrate > 0) {
452 $media['bitrate'] = $node->video_bitrate;
453 }
454 if (isset($node->videox) && isset($node->videoy) && $node->videox > 0) {
455 $media['width'] = $node->videox;
456 $media['height'] = $node->videoy;
457 }
458 if (isset($node->audio_sampling_rate) && $node->audio_sampling_rate > 0) {
459 $media['samplingrate'] = $node->audio_sampling_rate;
460 }
461 $mrss = array('key' => 'media:content', 'attributes' => $media);
462
463 // work around for http://drupal.org/node/157709
464 static $been_here = FALSE;
465 if (! $been_here) {
466 $mrss['namespace'] = array('xmlns:media="http://search.yahoo.com/mrss/"');
467 $been_here = TRUE;
468 }
469 }
470 return array($enclosure, $mrss);
471
472 case 'revision delete':
473 db_query('DELETE FROM {video} WHERE vid = %d', $node->vid);
474 break;
475 }
476 }
477
478
479 /**
480 * Create video submission page. Let the user select the actived video types
481 * or display the video form for the selected video type
482 */
483 function video_add() {
484 global $user;
485
486 $edit = isset($_POST['edit']) ? $_POST['edit'] : '';
487
488 // If a video type has been specified, validate its existence.
489
490 $vtypes = video_get_types();
491
492 if (arg(3) && in_array(arg(3), $vtypes)) { // is a valid video type
493 $type = arg(3);
494
495 // Initialize settings:
496 module_load_include('inc', 'node', 'node.pages');
497 $node = (object) array('uid' => $user->uid, 'name' => $user->name, 'type' => 'video', 'vtype' => $type);
498 $output = drupal_get_form('video_node_form', $node);
499 drupal_set_title(t('Submit %name video', array('%name' => $type)));
500 }
501 else if (count($vtypes) == 1) { // only one vtype active. redirect the user to the active type form
502 // Initialize settings:
503 $node = (object) array('uid' => $user->uid, 'name' => $user->name, 'type' => 'video', 'vtype' => $vtypes[0]);
504 module_load_include('inc', 'node', 'node.pages');
505 $output = drupal_get_form('video_node_form', $node);
506 drupal_set_title(t('Submit %name video', array('%name' => $vtypes[0])));
507 }
508 else if ($vtype = variable_get('video_default_video_type', 0)) {
509 // Initialize settings:
510 $node = (object) array('uid' => $user->uid, 'name' => $user->name, 'type' => 'video', 'vtype' => $vtype);
511 module_load_include('inc', 'node', 'node.pages');
512 $output = drupal_get_form('video_node_form', $node);
513 drupal_set_title(t('Submit %name video', array('%name' => $vtype)));
514 }
515 else {
516 $output = video_types_page();
517 }
518 return $output;
519 }
520
521
522 /**
523 * Display a video types selection page
524 */
525 function video_types_page() {
526
527 drupal_set_title(t('Submit Video')); // we have to set a titl ebecause the node module will not do it for us as we are using a callback video_add()
528
529 $vtypes = video_get_types_infos();
530 if(!$vtypes) { // no vtype available
531 return t('There are no Video types enabled.');
532 }
533 else {
534 $items = array();
535 foreach ($vtypes as $vtype => $infos) {
536 $out = '<dt>'. l($infos['#name'], "node/add/video/$vtype", array('HTML'=>TRUE, 'attributes' => array('title' => 'Add a '. $infos['#name']))) .'</dt>';
537 $out .= '<dd>'. $infos['#description'] .'</dd>';
538 $items[$vtype] = $out;
539 }
540 // let's order by type name
541 ksort($items);
542 return t('Choose from the following available video types:') .'<dl>'. implode('', $items) .'</dl>';
543 }
544 }
545
546
547 /**
548 * Return an array containing enabled Video Types
549 */
550 function video_get_types(){
551 return array_keys(video_get_types_infos());
552 }
553
554
555 /**
556 * Return an array containing informations on enabled Video Types
557 */
558 function video_get_types_infos(){
559 static $infos = NULL;
560
561 if(!is_array($infos)) {
562 $infos = module_invoke_all('v_info');
563 }
564 return $infos;
565 }
566
567
568 /**
569 * Return the informations for a given video type
570 */
571 function video_get_type_info($type) {
572 return module_invoke('video_'.$type, 'v_info');
573 }
574
575
576 /**
577 * Return true if a given video type is downloadable
578 */
579 function video_support_download($node) {
580 $info = video_get_type_info($node->vtype);
581 return $info[$node->vtype]['#downloadable'];
582 }
583
584
585
586 /**
587 * Hook, displays the contents of the node form page for creating and editing nodes.
588 *
589 * @param $node
590 * object
591 *
592 * @return
593 * string value of form content
594 */
595 function video_form($node) {
596 //We must unserialize the array for display in the forms.
597 if($node->serial_data) {
598 $node->serial_data = unserialize($node->serialized_data);
599 }
600 $form = array();
601
602 // default node stuff
603 $type = node_get_types('type', $node);
604
605 $form['title'] = array(
606 '#type' => 'textfield',
607 '#title' => check_plain($type->title_label),
608 '#size' => 60,
609 '#maxlength' => 128,
610 '#required' => TRUE,
611 '#default_value' => $node->title,
612 '#weight' => -20
613 );
614
615 if ($type->has_body) {
616 $form['body_filter']['body'] = array(
617 '#type' => 'textarea',
618 '#title' => check_plain($type->body_label),
619 '#required' => ($type->min_word_count > 0),
620 '#rows' => 10,
621 '#default_value' => $node->body,
622 );
623 $form['body_filter']['format'] = filter_form($node->format);
624 }
625
626 // set an hidden field to store video type
627 $form['vtype'] = array(
628 '#type' => 'hidden',
629 '#value' => $node->vtype
630 );
631
632 $form['video'] = array('#type' => 'fieldset', '#title' => t('Video Information'), '#weight' => -19);
633
634 if(!video_support_autoresolution($node)) { // this vtype doesn't support autoresolution
635 // let's display the resolution selection
636 $form['video']['vresolution'] = array(
637 '#type' => 'select',
638 '#title' => t('Resolution'),
639 '#description' => t("Select the approriate resolution (aspect ratio) for your video.<br />If you don't know what to choose then the default value will probably be ok for you."),
640 '#options' => _video_get_resolution_options(),
641 '#default_value' => _video_get_resolution_selected_option($node),
642 '#required' => true,
643 );
644 }
645 else {
646 // set an hidden field to store video resolution
647 $form['hvresolution'] = array(
648 '#type' => 'hidden',
649 '#value' => $node->videox . 'x' . $node->videoy
650 );
651 }
652
653 if(!video_support_autoplaytime($node)) { // this vtype doesn't support autoplaytime
654 $form['video']['playtime'] = array(
655 '#type' => 'fieldset',
656 '#title' => t('Playtime'),
657 '#collapsible' => true,
658 '#collapsed' => ($node->playtime_seconds) ? false : true, // display expanded if we have values inserted by the user
659 '#description' => t('Insert here the duration of the video.<br />Values may be entered in excess of their normal "clock maximum" (the seconds field may be 3600 to represent 1 hour), however each value will be summed for a total of all three.'));
660 $playtime = _video_sec2hms($node->playtime_seconds);
661 $form['video']['playtime']['playtime_hours'] = array(
662 '#type' => 'textfield',
663 '#title' => t('Hours'),
664 '#size' => 11,
665 '#maxlength' => 11,
666 '#default_value' => $playtime['hours'],
667 );
668 $form['video']['playtime']['playtime_minutes'] = array(
669 '#type' => 'textfield',
670 '#title' => t('Minutes'),
671 '#size' => 11,
672 '#maxlength' => 11,
673 '#default_value' => $playtime['minutes'],
674 );
675 $form['video']['playtime']['playtime_seconds'] = array(
676 '#type' => 'textfield',
677 '#title' => t('Seconds'),
678 '#required' => FALSE,
679 '#size' => 11,
680 '#maxlength' => 11,
681 '#default_value' => $playtime['seconds'],
682 );
683 }
684 else {
685 // set an hidden field to store video length
686 $form['playtime_seconds'] = array(
687 '#type' => 'hidden',
688 '#value' => $node->playtime_seconds
689 );
690 // we need to store file size too
691 $form['hsize'] = array(
692 '#type' => 'hidden',
693 '#value' => $node->size
694 );
695 }
696
697 // Get the video-type-specific bits.
698 $form = module_invoke('video_' . $node->vtype, 'v_form', $node, $form);
699
700 return $form;
701 }
702
703
704 /**
705 * Implementation of hook_validate
706 */
707 function video_validate($node, $form = array()) {
708 if(!video_support_autoresolution($node) || $node->vresolution) { // we have some resolution value
709 // form api checked for good values of vresolution
710 if(variable_get("video_{$node->vresolution}_value", '') == '') {
711
712 }
713 }
714
715 module_invoke('video_'.$node->vtype, 'v_validate', $node);
716
717 }
718
719
720 /**
721 * Implementation of hook submit
722 */
723 function video_presave(&$node) {
724 if(video_support_autoresolution($node) && ($node->new_video_upload_file_fid)) { // vtype support autoresolution getting
725 $xy = module_invoke('video_' . $node->vtype, 'v_auto_resolution', $node);
726 if ($xy) {
727 $node->videox = $xy[0];
728 $node->videoy = $xy[1];
729 }
730 }
731 else {
732 // if you have a existing value from hidden field
733 if($node->hvresolution) {
734 $res = explode('x', $node->hvresolution);
735 $node->videox = $res[0];
736 $node->videoy = $res[1];
737 $node->size = $node->hsize;
738 }
739 // we should have a good value (checked by Form API)
740 else {
741 $res = explode('x', variable_get('video_resolution_' . $node->vresolution . '_value', ''));
742 $node->videox = $res[0];
743 $node->videoy = $res[1];
744 }
745 }
746
747 if(video_support_autoplaytime($node) && ($node->new_video_upload_file_fid)) { // vtype support auto playtime
748 $node->playtime_seconds = module_invoke('video_' . $node->vtype, 'v_auto_playtime', $node);
749 }
750 else { // vtype does not support auto_playtime
751 $node->playtime_seconds += ($node->playtime_hours * 3600) + ($node->playtime_minutes * 60);
752 }
753 }
754
755 /**
756 * Implementation of hook_insert.
757 * Create video record in the video table
758 *
759 * @return
760 * TRUE on success, FALSE on error
761 */
762 function video_insert($node) {
763 // set the required properties of the video node
764 video_presave($node);
765 $node->serialized_data = serialize($node->serial_data); //Serialize the data for insertion into the database.
766
767 return db_query("INSERT INTO {video} (vid, nid, vtype, vidfile, size, videox, videoy, video_bitrate, audio_bitrate, audio_sampling_rate, audio_channels, playtime_seconds, disable_multidownload, download_folder, use_play_folder, serialized_data) VALUES (%d, %d, '%s', '%s', %d, %d, %d, %d, %d, %d, '%s', %d, %d, '%s', %d, '%s')",
768 $node->vid, $node->nid, $node->vtype, $node->vidfile, $node->size, $node->videox, $node->videoy, $node->video_bitrate, $node->audio_bitrate, $node->audio_sampling_rate, $node->audio_channels, $node->playtime_seconds, $node->disable_multidownload, $node->download_folder, $node->use_play_folder, $node->serialized_data);
769 }
770
771
772 /**
773 * Hook
774 *
775 * @return
776 * TRUE on success, FALSE on error
777 */
778 function video_update($node) {
779 if ($node->revision) { //If a new node revision is being added then insert a new row.
780 return video_insert($node);
781 }
782 else {
783 // set the required properties of the video node
784 video_presave($node);
785 $node->serialized_data = serialize($node->serial_data); //Serialize the data for insertion into the database.
786
787 return db_query("UPDATE {video} SET vidfile='%s', size=%d, videox=%d, videoy=%d, video_bitrate=%d, audio_bitrate=%d, audio_sampling_rate=%d, audio_channels='%s', playtime_seconds=%d, disable_multidownload=%d, download_folder='%s', use_play_folder=%d, serialized_data='%s' WHERE vid = %d",
788 $node->vidfile, $node->size, $node->videox, $node->videoy, $node->video_bitrate, $node->audio_bitrate, $node->audio_sampling_rate, $node->audio_channels, $node->playtime_seconds, $node->disable_multidownload, $node->download_folder, $node->use_play_folder, $node->serialized_data, $node->vid);
789 }
790 }
791
792
793
794 /**
795 * Implementation of hook_delete
796 */
797 function video_delete($node) {
798 db_query("DELETE FROM {video} WHERE nid = %d", $node->nid);
799 }
800
801
802
803 /**
804 * Implementation of hook_load()
805 *
806 * @param $node
807 * object or boolean FALSE on error
808 */
809 function video_load($node) {
810
811 if (is_numeric($node->vid)) {
812 $node = db_fetch_object(db_query("SELECT * FROM {video} WHERE vid = %d", $node->vid));
813
814 // load serialized data for plug-ins
815 $node->serial_data = unserialize($node->serialized_data);
816
817 return $node;
818 }
819 else {
820 return false;
821 }
822 }
823
824 /**
825 * Implementation of hook_view().
826 */
827 function video_view(&$node, $teaser = FALSE, $page = FALSE) {
828
829 // include the video css file
830 drupal_add_css(drupal_get_path('module', 'video').'/video.css');
831
832 //Run the body through the standard filters.
833 $node = node_prepare($node, $teaser);
834 //print_r($node);
835 //exit;
836 // theme the teaser
837 $node->teaser = theme('video_teaser', $node, $teaser, $page);
838
839 // if we are viewing the page, run the body through the theme
840 if ($page) {
841 $output = '';
842 if (user_access('play video')) {
843 $node->content['video_player'] = array('#value' => theme('video_player', $node), '#weight' => -1);
844 }
845 else {
846 $output .= l(t('login'), "user/login", array('class' => 'outgoing', 'title' => t('login to your account')));
847 $output .= ' ' . t('or') . ' ';
848 $output .= l(t('register'), "user/register", array('class' => 'outgoing', 'title' => t('create a new account')));
849 $output .= ' ' . t('to play video');
850
851 $node->content['video_player'] = array('#value' => $output, '#weight' => -1);
852 }
853 }
854
855 return $node;
856 }
857
858 /********************************************************************
859 * Block display functions
860 ********************************************************************/
861
862 /**
863 * Hook block. Does all the interaction with the drupal block system. Uses video_block_list() for DB queries.
864 *
865 * @param $op
866 * string type of block
867 *
868 * @param $delta
869 * integer 0 for latest, 1 for played+downloaded, 2 for most played, 3 for most downloaded.
870 *
871 * @param $edit
872 * array holds the data submitted by the configure forms.
873 *
874 * @return
875 * array
876 */
877 function video_block($op = 'list', $delta = 0, $edit = array()) {
878 if ($op == 'list') {
879 $blocks[0]['info'] = t('Latest videos');
880 $blocks[1]['info'] = t('Top videos');
881 $blocks[2]['info'] = t('Most played videos');
882 $blocks[3]['info'] = t('Most downloaded');
883 $blocks[4]['info'] = t('Random video');
884 return $blocks;
885 }
886 else if ($op == 'view') {
887 switch ($delta) {
888 case 0:
889 return array(
890 'subject' => variable_get('video_block_title_0', t('Latest videos')),
891 'content' => video_block_list($delta)
892 );
893 case 1:
894 return array(
895 'subject' => variable_get('video_block_title_1', t('Top videos')),
896 'content' => video_block_list($delta)
897 );
898 case 2:
899 return array(
900 'subject' => variable_get('video_block_title_2', t('Most played videos')),
901 'content' => video_block_list($delta)
902 );
903 case 3:
904 return array(
905 'subject' => variable_get('video_block_title_3', t('Most downloaded')),
906 'content' => video_block_list($delta)
907 );
908 case 4:
909 return array(
910 'subject' => variable_get('video_block_title_4', t('Random video')),
911 'content' => video_block_list($delta)
912 );
913 }
914 }
915 else if ($op == 'configure') {
916 switch ($delta) { //Get the default title of the block incase the variable is not set yet.
917 case 0:
918 $default_title = t('Latest videos');
919 break;
920 case 1:
921 $default_title = t('Top videos');
922 break;
923 case 2:
924 $default_title = t('Most played videos');
925 break;
926 case 3:
927 $default_title = t('Most downloaded');
928 break;
929 case 4:
930 $default_title = t('Random video');
931 }
932 $form['video_block_title'] = array(
933 '#type' => 'textfield',
934 '#title' => t('Block display title'),
935 '#default_value' => variable_get("video_block_title_$delta", $default_title));
936 $form['video_block_limit'] = array(
937 '#type' => 'select',
938 '#title' => t('Number of videos to list in block'),
939 '#default_value' => variable_get("video_block_limit_$delta", 10),
940 '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)));
941 return $form;
942 }
943 else if ($op == 'save') {
944 variable_set("video_block_title_$delta", $edit['video_block_title']);
945 variable_set("video_block_limit_$delta", $edit['video_block_limit']);
946 }
947 }
948
949 /**
950 * Query DB for block content
951 *
952 * @param $delta
953 * int 0, 1, 2, or 3. Determines which type of block is being accessed.
954 *
955 * @return
956 * string HTML content for a block
957 */
958 function video_block_list($delta = 0) {
959 $count = variable_get("video_block_limit_$delta", 10);
960 switch ($delta) {
961 case 0:
962 $orderby = 'n.created';
963 break;
964 case 1:
965 $orderby = 'v.download_counter + v.play_counter';
966 break;
967 case 2:
968 $orderby = 'v.play_counter';
969 break;
970 case 3:
971 $orderby = 'v.download_counter';
972 break;
973 case 4:
974 $count = 1;
975 $orderby = 'RAND()';
976 break;
977 }
978 return node_title_list(db_query_range(db_rewrite_sql("SELECT n.nid, n.title, $orderby FROM {node} n INNER JOIN {video} v ON n.vid = v.vid WHERE n.type = 'video' AND n.status = 1 AND n.moderate = 0 ORDER BY $orderby DESC"),0, $count));
979 }
980
981 /****************************************************
982 * Menu callback functions
983 ****************************************************/
984
985 /**
986 * Redirects to download the video file.
987 */
988 function video_download($node) {
989 // $node as been loaded by video_menu
990 print_r($node);
991 exit;
992 if ($node) {
993 if (video_support_download($node) && _video_allow_download($node)) { //Make sure the video type is not youtube before downloading.
994 _video_download_goto($node);
995 }
996 else { //If video is type youtube then it can't be downloaded.
997 drupal_set_message(t('There are no files to download for this video.'), 'error');
998 print theme('page', '');
999 }
1000 }
1001 else {
1002 drupal_not_found();
1003 }
1004 }
1005
1006
1007 /**
1008 * Return true if the video is downloadable, false otherwise
1009 */
1010 function _video_allow_download($node) {
1011 // TODO: now videos are downloadable by default. why not implementing a feature to let users choose if they want their videos to be downloadable?
1012
1013 return true;
1014 }
1015
1016
1017 /**
1018 * Theme the teaser
1019 *
1020 * This is just in place for site admins and theme developers
1021 * who need to adjust how the teaser is themed.
1022 *
1023 * @param $node
1024 * The node to be displayed.
1025 * @param $teaser
1026 * Whether we are to generate a "teaser" or summary of the node, rather than display the whole thing.
1027 * @param $page
1028 * Whether the node is being displayed as a standalone page. If this is TRUE, the node title should not be displayed, as it will be printed automatically by the theme system. Also, the module may choose to alter the default breadcrumb trail in this case.
1029 *
1030 * @return
1031 * html
1032 */
1033 function theme_video_teaser($node, $teaser = FALSE, $page = FALSE) {
1034 return $node->teaser;
1035 }
1036
1037 /**
1038 * theme the view of the page to include the video
1039 * assumes that body was put through prepare in hook_view
1040 *
1041 * @param $node
1042 * The node to be displayed.
1043 * @param $teaser
1044 * Whether we are to generate a "teaser" or summary of the node, rather than display the whole thing.
1045 * @param $page
1046 * Whether the node is being displayed as a standalone page. If this is TRUE, the node title should not be displayed, as it will be printed automatically by the theme system. Also, the module may choose to alter the default breadcrumb trail in this case.
1047 *
1048 * @return
1049 * html
1050 */
1051 function theme_video_view($node, $teaser = FALSE, $page = FALSE) {
1052 return '<div id="video_body">'. $node->body .'</div>';
1053 }
1054
1055 /**
1056 * theme function to control which player is presented
1057 *
1058 * @param $node
1059 * node object
1060 *
1061 * @return
1062 * html
1063 */
1064 function theme_video_player($node) {
1065 // include video.js file for Internet Explorer fixes
1066 //theme('video_get_script');
1067 drupal_add_js(drupal_get_path('module', 'video') . '/video.js');
1068 if (variable_get('video_playcounter', 1)) {
1069 db_query("UPDATE {video} SET play_counter = play_counter + 1 where vid = %d", $node->vid); //Increment play counter.
1070 }
1071
1072 _video_scale_video($node);
1073 $output = module_invoke('video_'.$node->vtype, 'v_play', $node);
1074
1075 return $output;
1076 }
1077
1078
1079 /**
1080 * Cut down on redundant link text
1081 *
1082 * @param $url
1083 * string URL to link to
1084 *
1085 * @param $title
1086 * string title of link to show on mouseover
1087 *
1088 * @param $link_text
1089 * string text of the link
1090 *
1091 * @return
1092 * string HTML link
1093 */
1094 function theme_video_format_play($output, $url, $title, $link_text) {
1095 $output = "\n<div id=\"video-player\">\n" . $output;
1096 $output .= "<p>\n". t('Problems viewing videos?');
1097 $output .= "<br />\n";
1098 $output .= l($link_text, $url, array('attributes' => array('title' => $title), 'absolute' => TRUE));
1099 return $output ."\n</p> \n </div>\n";
1100 }
1101
1102
1103 /**
1104 * Takes an associative array of $fields with 'title' and 'body' keys and outputs the HTML.
1105 * This theme function allows the same HTML code to generate all the custom and metadata fields.
1106 *
1107 * @param $fields
1108 * array with 'title' and 'body' keys
1109 *
1110 * @return
1111 * string of content to display
1112 */
1113 function theme_video_fields($fields) {
1114 $output = '';
1115 $odd_even = 'odd';
1116 foreach ($fields as $field) {
1117 $output .= "<div class=\"$odd_even\"><b>" . check_plain($field['title']) . '</b> ' . check_plain($field['body']) . "</div>\n";
1118 $odd_even = ($odd_even == 'odd') ? 'even' : 'odd'; //Always switch its value.
1119 }
1120 return $output;
1121 }
1122
1123
1124 /**
1125 * Import the video.js script
1126 */
1127 function theme_video_get_scripvt() {
1128 drupal_add_js(drupal_get_path('module', 'video') . '/video.js');
1129 }
1130
1131 /******************************************************************************
1132 * End theme functions
1133 ******************************************************************************
1134 * Start private functions created for this module.
1135 ******************************************************************************/
1136
1137 /**
1138 * Pull the file extension from a filename
1139 *
1140 * @param $vidfile
1141 * string filename to get the filetype from.
1142 *
1143 * @return
1144 * string value of file type or boolean FALSE on error
1145 */
1146 function _video_get_filetype($vidfile) {
1147 //If the filename doesn't contain a ".", "/", or "\" and is exactly 11 characters then consider it a youtube video ID.
1148 if (!strpos($vidfile, '.') and !strpos($vidfile, '/') and !strpos($vidfile, '\\') and strlen($vidfile) == 11) {
1149 $file_type = 'youtube';
1150 }
1151 else if (strpos($vidfile, 'google:') === 0) {
1152 $file_type = 'googlevideo';
1153 }
1154 else if (strstr($vidfile, '.')) { //If file contains a "." then get the file extension after the "."
1155
1156 $file_type = end(explode('.', $vidfile));
1157 }
1158 else {
1159 $file_type = FALSE;
1160 }
1161
1162 return strtolower($file_type);
1163 }
1164
1165 /**
1166 * Forward user directly to the file for downloading
1167 *
1168 */
1169 function _video_download_goto($node) {
1170 if (user_access('download video')) {
1171
1172 if (variable_get('video_downloadcounter', 1)) {
1173 db_query("UPDATE {video} SET download_counter = download_counter + 1 where vid = %d", $node->vid); //Increment download counter.
1174 }
1175
1176 // let the submodule handle the real download logic
1177 module_invoke('video_'.$node->vtype, 'v_download', $node);
1178 }
1179 else { //If the user does not have access to download videos.
1180 drupal_set_message(t('You do not have permission to download videos.'), 'error');
1181