* @author David Norman * @author Luke Last */ /******************************************************************** * General Hooks ********************************************************************/ /** * Help hook * * @param $section * string of the area of Drupal where help was requested * * @return * string of help information */ function video_help($section = 'admin/help#video') { switch ($section) { case 'admin/help#video': $output = '

' . t('The video module (4.7 or with backport patch to 4.6) allows users to post video content to their site. The emergence of portable phones with video capture capabilities has made video capture ubiquitous. Video logging, or vlogging as a medium for personal video broadcasting has proven to be popular and is following the blogging, and podcasting phenomena\'s. Videos are useful for creative collaboration among community members. If community members can not meet in person videos of meetings are valuable for enhancing the interaction between community members.', array('%elink-en-wikipedia-org' => 'http://en.wikipedia.org/wiki/Vlog')) . '

'; $output .= '

' . t('The video module can be administered to flash player settings. There are a number of page and menu links which can be added to play and download video content on the site. Other configurable options include play and download counters. Multi-file downloads can also be configured under settings. There are also up to six custom fields and a group name which can be added.') . '

'; $output .= t('

You can:

', array('%admin-block' => url('admin/settings/block'), '%node-add-video' => url('node/add/video'), '%admin-settings-video' => url('admin/content/video'))); $output .= '

'. t('For more information please read the configuration and customization handbook Video page.', array('%video' => 'http://www.drupal.org/handbook/modules/video/')) .'

'; return $output; case 'admin/settings/modules#description': return t('Allows video nodes.'); case 'node/add#video': return t('Allows you to insert videos as nodes.'); case 'video/help': $help = ''; $help .= '

' . t('Video File Field') . '

'; $help .= '

' . t('This is the field where you enter the video file information. The Video module currently supports these file types:') . '

'; $help .= ''; $help .= '

' . t('Multi-file Dowload Help') . '

'; $help .= '

' . t('If enabled, this group holds all the settings for multi-file downloads. Multi-file downloads allows you to have a list of any number of files on the download page. These files are usually scanned from a folder. This allows the listing of multiple sizes and video types for visitors to choose from, you can even zip the files up.') . '

'; $help .= ''; return $help; } } /** * Implementation of hook_menu(). * * @param $may_cache * boolean indicating whether cacheable menu items should be returned * * @return * array of menu information */ function video_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array( 'path' => 'video', 'title' => t('videos'), 'callback' => 'video_page', 'access' => user_access('access video'), 'type' => MENU_SUGGESTED_ITEM); $items[] = array( 'path' => 'video/feed', 'title' => t('videos feed'), 'callback' => 'video_feed', 'access' => user_access('access video'), 'type' => MENU_CALLBACK); $items[] = array( 'path' => 'node/add/video', 'title' => t('video'), 'access' => user_access('create video')); $items[] = array( 'path' => 'admin/content/video', 'title' => t('video settings'), 'description' => t('administer video module settings'), 'callback' => 'drupal_get_form', 'callback arguments' => array('video_settings_form'), 'access' => user_access('administer site configuration'), 'type' => MENU_NORMAL_ITEM, ); } else { //If $may_cache is false. if (arg(0) == 'node' && is_numeric(arg(1))) { if ($node = node_load(arg(1)) and $node->type == 'video') { if (variable_get('video_displayplaymenutab', 1) == 1) { $menu_type = MENU_LOCAL_TASK; } else { $menu_type = MENU_CALLBACK; } $items[] = array('path' => 'node/'. arg(1) .'/play', 'title' => t('play'), 'callback' => 'video_play', 'access' => user_access('play video'), 'weight' => 3, 'type' => $menu_type); //If the video is of type youtube and multi-file downloads aren't turned on don't show the download tab. if (variable_get('video_displaydownloadmenutab', 1) == 1 and (_video_get_filetype($node->vidfile) != 'youtube' and _video_get_filetype($node->vidfile) != 'googlevideo')) { $items[] = array('path' => 'node/'.arg(1).'/download', 'title' => t('download'), 'callback' => 'video_download', 'access' => user_access('access video'), 'weight' => 5, 'type' => MENU_LOCAL_TASK); } } } } return $items; } /** * Implementation of hook_init() * Currently just does a check for whether the views module exists and, * if it does loads the video views module. */ function video_init() { if (module_exist('views')) { include(drupal_get_path('module', 'video') .'/views_video.inc'); } } /** * Internal Drupal links hook * * @param $type * string type of link to show * * @param $node * object of node information * * @return * array of link information */ function video_link($type, $node = NULL) { $link = array(); // Node links for a video if ($type == 'node' && $node->type == 'video' && $node->vidfile && user_access('access video')) { //If the video is of type youtube and multi-file downloads aren't turned on don't show the download link. if ((_video_get_filetype($node->vidfile) == 'youtube' or _video_get_filetype($node->vidfile) == 'googlevideo') and $node->disable_multidownload == 1) { $display_download_link = 0; } else { $display_download_link = variable_get('video_displaydownloadlink', 1); } if (user_access('play video')) { if (variable_get('video_displayplaylink', 1)) { $link['video_play'] = array( 'title' => t('play'), 'href' => "node/$node->nid/play", 'attributes' => array( 'class' => 'outgoing', 'title' => t('play %link', array('%link' => $node->title)), ), ); } } if ($display_download_link == 1) { $link['video_download'] = array( 'title' => t('download'), 'href' => "node/$node->nid/download", 'attributes' => array( 'class' => 'outgoing', 'title' => t('download %link', array('%link' => $node->title)), ), ); } } return $link; } /** * Displays a Drupal page containing recently added videos * * @return * string HTML output */ function video_page() { $output = ''; if (arg(1) != 'help') { //We are not reading help so output a list of recent video nodes. $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)); while ($node = db_fetch_object($result)) { $output .= node_view(node_load($node->nid), 1); } $output .= theme('pager', NULL, variable_get('default_nodes_main', 10)); // adds feed icon and link drupal_add_link(array('rel' => 'alternate', 'type' => 'application/rss+xml', 'title' => variable_get('site_name', 'drupal') . ' ' . t('videos'), 'href' => url('video/feed/'))); $output .= '
' . theme('feed_icon', url('video/feed')); } return $output; } /** * Generate an RSS feed for videos * * @return * feed */ function video_feed() { $channel = array( 'title' => variable_get('site_name', 'drupal') . ' ' . t('videos'), 'description' => t('Latest videos on') . ' ' . variable_get('site_name', 'drupal'), 'link' => url('video', NULL, NULL, TRUE) ); $result = db_query('SELECT n.nid FROM {node} n WHERE n.type = "video" AND n.status = 1 ORDER BY n.created DESC'); node_feed($result, $channel); } /** * Permissions hook * * @return * array of permissions */ function video_perm() { $array = array('create video', 'access video', 'administer video', 'play video', 'download video', 'view play counter', 'view download counter', 'edit own video'); return $array; } /** * Settings Hook * * @return * string of form content or error message */ function video_settings_form() { global $base_url; //Must have "administer site configuration" and "administer video" privilages. if (!user_access('administer video')) { drupal_access_denied(); } $options = array(1 => 'Yes', 0 => 'No'); $form = array(); $form['tabs'] = array('#type' => 'fieldset', '#title' => t('Tab menu options'), '#collapsible' => TRUE, '#collapsed' => TRUE); $form['tabs']['video_displayplaymenutab'] = array( '#type' => 'radios', '#title' => t('Display play menu tab'), '#options' => $options, '#default_value' => variable_get('video_displayplaymenutab', 1), '#description' => t('Toggle display of menu link to play video from the node page.')); $form['tabs']['video_displaydownloadmenutab'] = array( '#type' => 'radios', '#title' => t('Display download menu tab'), '#options' => $options, '#default_value' => variable_get('video_displaydownloadmenutab', 1), '#description' => t('Toggle display of menu link to download video from the node page.')); $form['flash'] = array('#type' => 'fieldset', '#title' => t('Flash settings'), '#collapsible' => TRUE, '#collapsed' => TRUE); $form['flash']['video_flvplayerloader'] = array( '#type' => 'textfield', '#title' => t('Filename of Flash loader'), '#default_value' => variable_get('video_flvplayerloader', 'Player.swf'), '#description' => t('The name of the Shockwave file that manages loading the FLV movie.')); $form['ogg'] = array('#type' => 'fieldset', '#title' => t('Ogg Theora settings'), '#collapsible' => TRUE, '#collapsed' => TRUE); $form['ogg']['video_cortado'] = array( '#type' => 'textfield', '#title' => t('Filename of Cortado Java Applet'), '#default_value' => variable_get('video_cortado', $base_url . '/cortado.jar'), '#description' => t('The path to the Cortado Applet to play Ogg Theora Files.')); $form['menu'] = array('#type' => 'fieldset', '#title' => t('Items to display in the node menu'), '#weight' => -5, '#collapsible' => TRUE, '#collapsed' => TRUE); $form['menu']['video_displayplaylink'] = array( '#type' => 'radios', '#title' => t('Display play link'), '#options' => $options, '#default_value' => variable_get('video_displayplaylink', 1), '#description' => t('Toggle display of "play" link (below the node content in most themes).')); $form['menu']['video_displaydownloadlink'] = array( '#type' => 'radios', '#title' => t('Display download link'), '#options' => $options, '#default_value' => variable_get('video_displaydownloadlink', 1), '#description' => t('Toggle display of "download" link (below the node content in most themes).')); $form['menu']['video_displayplaytime'] = array( '#type' => 'radios', '#title' => t('Display playtime'), '#options' => $options, '#default_value' => variable_get('video_displayplaytime', 1), '#description' => t('Toggle the display of the playtime for a video.')); $form['menu']['video_displayfilesize'] = array( '#type' => 'radios', '#title' => t('Display filesize'), '#options' => $options, '#default_value' => variable_get('video_displayfilesize', 1), '#description' => t('Toggle the display of the filesize for a video.')); $form['counters'] = array('#type' => 'fieldset', '#title' => t('Statistics counters'), '#description' => t('To allow users to view counters visit: ') . l(t('access control'), 'admin/access'), '#collapsible' => TRUE, '#collapsed' => TRUE); $form['counters']['video_playcounter'] = array( '#type' => 'radios', '#title' => t('Count play hits'), '#options' => $options, '#default_value' => variable_get('video_playcounter', 1), '#description' => t('Counts a hit everytime someone views the play page.')); $form['counters']['video_downloadcounter'] = array( '#type' => 'radios', '#title' => t('Count downloads'), '#options' => $options, '#default_value' => variable_get('video_downloadcounter', 1), '#description' => t('Counts a hit everytime someone downloads a video.')); return system_settings_form($form); } /****************************************************************************** * Node Hooks ******************************************************************************/ /** * Implementation of _node_info(). * * @return * array */ function video_node_info() { return array('video' => array( 'name' => t('video'), 'module' => 'video', 'description' => t('allow a variety of video formats to be posted as nodes in your site'), ) ); } /** * access hook */ function video_access($op, $node) { global $user; switch($op) { case 'view': return $node->status; // see book.module for reference case 'create': return user_access('create video'); case 'update': case 'delete': return user_access('edit own video') && ($user->uid == $node->uid); } } /** * Implementation of hook_nodeapi(). * We use this to append tags to the RSS feeds Drupal generates. */ function video_nodeapi($node, $op, $arg) { switch ($op) { case 'rss item': if ($node->type == 'video') { $attributes['url'] = _video_get_fileurl($node->vidfile); $attributes['length'] = $node->size; $mime_type = _video_get_mime_type($node); if ($mime_type) { $attributes['type'] = $mime_type; } $media['url'] = $attributes['url']; $media['fileSize'] = $attributes['length']; $media['type'] = $attributes['type']; return array(array('key' => 'enclosure', 'attributes' => $attributes), array('key' => 'media', 'value' => '', 'attributes' => $media)); } case 'revision delete': db_query('DELETE FROM {video} WHERE vid = %d', $node->vid); break; } } /** * Hook, displays the contents of the node form page for creating and editing nodes. * * @param $node * object * * @return * string value of form content */ function video_form($node) { //We must unserialize the array for display in the forms. $node->serial_data = unserialize($node->serialized_data); $form = array(); $form['title'] = array('#type' => 'textfield', '#title' => t('Title'), '#size' => 60, '#maxlength' => 128, '#required' => TRUE, '#default_value' => $node->title, '#weight' => -20); $form['body_filter']['body'] = array('#type' => 'textarea', '#title' => t('Body'), '#default_value' => $node->body, '#required' => FALSE, '#weight' => -15); $form['body_filter']['filter'] = filter_form($node->format); $form['log'] = array('#type' => 'fieldset', '#title' => t('Log message'), '#collapsible' => TRUE, '#collapsed' => TRUE); $form['log']['message'] = array( '#type' => 'textarea', '#default_value' => $node->log, '#rows' => 5, '#description' => t('An explanation of the additions or updates being made to help other authors understand your motivations.') ); $form['video'] = array('#type' => 'fieldset', '#title' => t('Video File'), '#weight' => -19); $form['video']['vidfile'] = array( '#type' => 'textfield', '#title' => t('Video File'), '#default_value' => $node->vidfile, '#maxlength' => 700, '#required' => TRUE, '#weight' => -20, '#description' => t('Put here the video file path. You can use either relative to the drupal root directory (something/video.mov) or absolute (http://www.example.com/videos/videos.mov). Windows Media currently requires a fully qualified URL to function. Flash movies may not play with spaces in the path or filename. To add youtube.com videos enter the video ID. If your video was at (http://www.youtube.com/watch.php?v=aBM4QYXPf-s) you would enter (aBM4QYXPf-s). To add Google videos you will need the docId values available on the embed code google provide with "google:" as heading. ') . l(t('More information.'), 'video/help', NULL, NULL, 'videofile')); $form['video']['videox'] = array( '#type' => 'textfield', '#title' => t('Video Size Width (x)'), '#required' => TRUE, '#length' => 4, '#maxlength' => 4, '#default_value' => $node->videox, '#description' => t('Horizontal video pixel size.')); $form['video']['videoy'] = array( '#type' => 'textfield', '#title' => t('Video Size Height (y)'), '#required' => TRUE, '#length' => 4, '#maxlength' => 4, '#default_value' => $node->videoy, '#description' => t('Vertical video pixel size.')); $form['video']['filesize'] = array('#type' => 'fieldset', '#title' => t('Filesize')); $form['video']['filesize']['size'] = array( '#type' => 'textfield', '#title' => t('Size'), '#required' => FALSE, '#length' => 12, '#maxlength' => 12, '#default_value' => $node->size, '#description' => t('If the video is on the local server the size will be set automatically. Otherwise enter a value. Entering 0 will turn the display off. Must be less than 2GB.')); $form['video']['filesize']['size_format'] = array( '#type' => 'select', '#title' => t('size units'), '#options' => array('B' => t('bytes'), 'Kb' => t('Kilobits'), 'KB' => t('KiloBytes'), 'Mb' => t('Megabits'), 'MB' => t('MegaBytes'), 'Gb' => t('Gigabits'), 'GB' => t('GigaBytes')), '#default_value' => 'B'); $form['video']['playtime'] = array('#type' => 'fieldset', '#title' => t('Playtime'), '#description' => t('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.')); $playtime = _video_sec2hms($node->playtime_seconds); $form['video']['playtime']['playtime_hours'] = array( '#type' => 'textfield', '#title' => t('Hours'), '#length' => 11, '#maxlength' => 11, '#default_value' => $playtime['hours'], '#description' => t('Integer of hours.')); $form['video']['playtime']['playtime_minutes'] = array( '#type' => 'textfield', '#title' => t('Minutes'), '#length' => 11, '#maxlength' => 11, '#default_value' => $playtime['minutes'], '#description' => t('Integer of minutes.')); $form['video']['playtime']['playtime_seconds'] = array( '#type' => 'textfield', '#title' => t('Seconds'), '#required' => TRUE, '#length' => 11, '#maxlength' => 11, '#default_value' => $playtime['seconds'], '#description' => t('Integer of seconds.')); return $form; } /** * Implementation of hook submit */ function video_submit(&$node) { _video_db_preprocess($node); //Make changes to data before updating DB. } /** * Hook: Create video record in video table * * @return * TRUE on success, FALSE on error */ function video_insert($node) { $node->serialized_data = serialize($node->serial_data); //Serialize the data for insertion into the database. return db_query("INSERT INTO {video} (vid, nid, vidfile, size, videox, videoy, video_bitrate, audio_bitrate, audio_sampling_rate, audio_channels, playtime_seconds, disable_multidownload, download_folder, use_play_folder, custom_field_1, custom_field_2, custom_field_3, custom_field_4, custom_field_5, custom_field_6, serialized_data) VALUES (%d, %d, '%s', %d, %d, %d, %d, %d, %d, '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s')", $node->vid, $node->nid, $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->custom_field_1, $node->custom_field_2, $node->custom_field_3, $node->custom_field_4, $node->custom_field_5, $node->custom_field_6, $node->serialized_data); } /** * Hook * * @return * TRUE on success, FALSE on error */ function video_update($node) { if ($node->revision) { //If a new node revision is being added then insert a new row. return video_insert($node); } else { $node->serialized_data = serialize($node->serial_data); //Serialize the data for insertion into the database. 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, custom_field_1='%s', custom_field_2='%s', custom_field_3='%s', custom_field_4='%s', custom_field_5='%s', custom_field_6='%s', serialized_data='%s' WHERE vid = %d", $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->custom_field_1, $node->custom_field_2, $node->custom_field_3, $node->custom_field_4, $node->custom_field_5, $node->custom_field_6, $node->serialized_data, $node->vid); } } /** * This function makes changes to node data before it is put into the database. * * @param $node * object a reference to a $node object to modify. * * @return * nothing */ function _video_db_preprocess(&$node) { //Calculate the time in seconds. $node->playtime_seconds += ($node->playtime_hours * 3600) + ($node->playtime_minutes * 60); //If video type is youtube or googlevideo, don't attempt to get filesize (googlevideo filenames are too long to stat) if (_video_get_filetype($node->vidfile) != 'youtube' and _video_get_filetype($node->vidfile) != 'googlevideo') { //If file is on the local server get size, otherwise get size from function. $path = getcwd() . '/' . $node->vidfile; //Local path to video file. $path_for_size = $path; // file_check_file will make $path unusable for filesize() if (file_check_path($path) && is_file($path_for_size)) { //If file exists locally set size. $node->size = filesize($path_for_size); } else { $node->size = _video_size2bytes($node); //Change the size to be correctly shown in bytes. } } } /** * Hook * * @param $node * object */ function video_delete($node) { db_query("DELETE FROM {video} WHERE nid = %d", $node->nid); } /** * Hook to see if every video field has been filled * and contains a valid value. * * @param $node * object */ function video_validate($node) { if (isset($node->vidfile)) { if ($node->vidfile != '') { //let's see if we have it yet $result = db_query("SELECT * from {video} WHERE vidfile = '%s' and nid <> %d", $node->vidfile, $node->nid); if (db_num_rows($result) > 0) { $video = db_fetch_object($result); $othernode = node_load($video->nid); form_set_error('vidfile', t('A video %link-to-existing using that link already exists', array("%link-to-existing" => l($othernode->title, 'node/' . $othernode->nid . '/edit')))); } } } if (_video_get_filetype($node->vidfile) != 'youtube' and _video_get_filetype($node->vidfile) != 'googlevideo') { //If video is of type youtube don't check size. if (isset($node->videox) && $node->videox <= 0) { form_set_error('videox', t('You have to insert a valid horizontal pixel size for this video')); } if (isset($node->videoy) && $node->videoy <= 0) { form_set_error('videoy', t('You have to insert a valid vertical pixel size for this video')); } } //Make sure file size is valid. $path = getcwd() . '/' . $node->vidfile; //Local path to video file. if ((!isset($node->size) || !is_numeric($node->size) || $node->size < 0) && !$_SESSION['video_upload_file']) { //If the file is not local or not a valid number then set error. $_SESSION check needed for video_upload functionality form_set_error('size', t('You have to insert a valid file size for this video.')); } //Makes sure the total playtime is greater than 0. $time = $node->playtime_seconds + $node->playtime_minutes + $node->playtime_hours; if ((isset($node->playtime_minutes) and isset($node->playtime_hours) and isset($node->playtime_seconds)) and $time == 0) { form_set_error('playtime_seconds', t('Please enter valid playtime information for this video.')); } } /** * Implementation of hook_load() * * @param $node * object or boolean FALSE on error */ function video_load($node) { if (is_numeric($node->vid)) { $node = db_fetch_object(db_query("SELECT * FROM {video} WHERE vid = %d", $node->vid)); // load serialized data for plug-ins $node->serial_data = unserialize($node->serialized_data); return $node; } else { return false; } } /** * Implementation of hook_view(). * In addition to standard uses, it adds the 6 custom fields to the body of the node. * * @return * Nothing, modifies $node which is passed by reference. */ function video_view(&$node, $teaser = FALSE, $page = FALSE) { $node = node_prepare($node, $teaser); //Run the body through the standard filters. // include the video css file drupal_add_css(drupal_get_path('module', 'video').'/video.css'); $node->content['body'] = array('#value' => $node->body); return $node; } /******************************************************************** * Block display functions ********************************************************************/ /** * Hook block. Does all the interaction with the drupal block system. Uses video_block_list() for DB queries. * * @param $op * string type of block * * @param $delta * integer 0 for latest, 1 for played+downloaded, 2 for most played, 3 for most downloaded. * * @param $edit * array holds the data submitted by the configure forms. * * @return * array */ function video_block($op = 'list', $delta = 0, $edit = array()) { if ($op == 'list') { $blocks[0]['info'] = t('Latest videos'); $blocks[1]['info'] = t('Top videos'); $blocks[2]['info'] = t('Most played videos'); $blocks[3]['info'] = t('Most downloaded'); $blocks[4]['info'] = t('Random video'); return $blocks; } else if ($op == 'view') { switch ($delta) { case 0: return array( 'subject' => variable_get('video_block_title_0', t('Latest videos')), 'content' => video_block_list($delta) ); case 1: return array( 'subject' => variable_get('video_block_title_1', t('Top videos')), 'content' => video_block_list($delta) ); case 2: return array( 'subject' => variable_get('video_block_title_2', t('Most played videos')), 'content' => video_block_list($delta) ); case 3: return array( 'subject' => variable_get('video_block_title_3', t('Most downloaded')), 'content' => video_block_list($delta) ); case 4: return array( 'subject' => variable_get('video_block_title_4', t('Random video')), 'content' => video_block_list($delta) ); } } else if ($op == 'configure') { switch ($delta) { //Get the default title of the block incase the variable is not set yet. case 0: $default_title = t('Latest videos'); break; case 1: $default_title = t('Top videos'); break; case 2: $default_title = t('Most played videos'); break; case 3: $default_title = t('Most downloaded'); break; case 4: $default_title = t('Random video'); } $form['video_block_title'] = array( '#type' => 'textfield', '#title' => t('Block display title'), '#default_value' => variable_get("video_block_title_$delta", $default_title)); $form['video_block_limit'] = array( '#type' => 'select', '#title' => t('Number of videos to list in block'), '#default_value' => variable_get("video_block_limit_$delta", 10), '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))); return $form; } else if ($op == 'save') { variable_set("video_block_title_$delta", $edit['video_block_title']); variable_set("video_block_limit_$delta", $edit['video_block_limit']); } } /** * Query DB for block content * * @param $delta * int 0, 1, 2, or 3. Determines which type of block is being accessed. * * @return * string HTML content for a block */ function video_block_list($delta = 0) { $count = variable_get("video_block_limit_$delta", 10); switch ($delta) { case 0: $orderby = 'n.created'; break; case 1: $orderby = 'v.download_counter + v.play_counter'; break; case 2: $orderby = 'v.play_counter'; break; case 3: $orderby = 'v.download_counter'; break; case 4: $count = 1; $orderby = 'RAND()'; break; } 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)); } /**************************************************** * Menu callback functions ****************************************************/ /** * Redirects to download the video file. */ function video_download() { if ($node = node_load(arg(1))) { if (_video_get_filetype($node->vidfile) != 'youtube' and _video_get_filetype($node->vidfile) != 'googlevideo') { //Make sure the video type is not youtube before downloading. _video_download_goto($node->vidfile, $node->vid); } else { //If video is type youtube then it can't be downloaded. drupal_set_message(t('There are no files to download for this video.'), 'error'); print theme('page', ''); } } else { drupal_not_found(); } } /** * Implements play callback function from node menu */ function video_play() { if ($node = node_load(arg(1))) { // include video.js file for Internet Explorer fixes theme('video_get_script'); drupal_set_title(t('Playing') . ' ' . theme('placeholder', $node->title)); if (variable_get('video_playcounter', 1)) { db_query("UPDATE {video} SET play_counter = play_counter + 1 where vid = %d", $node->vid); //Increment play counter. } switch (_video_get_filetype($node->vidfile)) { case 'divx': return theme('video_play_divx', $node); case 'mov': case 'mp4': case '3gp': case '3g2': return theme('video_play_quicktime', $node); case 'rm': return theme('video_play_realmedia', $node); case 'flv': return theme('video_play_flash', $node); case 'swf': return theme('video_play_swf', $node); case 'dir': case 'dcr': return theme('video_play_dcr', $node); case 'wmv': return theme('video_play_windowsmedia', $node); case 'ogg': return theme('video_play_ogg_theora', $node); case 'youtube': return theme('video_play_youtube', $node); case 'googlevideo': return theme('video_play_googlevideo', $node); default: drupal_set_message('Video type not supported', 'error'); drupal_goto("node/$node->nid"); break; } } else { drupal_not_found(); } } /********************************************************************* * Themeable functions for playing videos. They print a page with a player embedded. *********************************************************************/ /** * Play videos from in FLV Flash video format * * @param $node * object with node information * * @return * string of content to display */ function theme_video_play_flash($node) { $loader_location = variable_get('video_flvplayerloader', 'FlowPlayer.swf'); $url = _video_get_fileurl($node->vidfile); $file = basename($url); $base_url = substr($url, 0, strrpos($url, '/')); // this will be executed by not Internet Explorer browsers $output = ' ' . "\n"; // this will be executed by Internet Explorer $output .= '' . "\n"; // params will be passed to both IE or not IE browsers $output .= ' ' . "\n" . _video_get_parameters($node) . '

'. t('Your browser is not able to display this multimedia content.') .'

'; $output = _theme_video_format_play($output, t('http://www.macromedia.com/go/getflashplayer'), t('Link to Macromedia Flash Player Download Page'), t('Download latest Flash Player')); return $output; } /** * Play Flash .swf files. * * @param $node * object with node information * * @return * string of content to display */ function theme_video_play_swf($node) { $url = _video_get_fileurl($node->vidfile); // this will be executed by not Internet Explorer browsers $output = ' ' . "\n"; // this will be executed by Internet Explorer $output .= '' . "\n"; // params will be passed to both IE or not IE browsers $output .= '' . "\n" . _video_get_parameters($node) . '

'. t('Your browser is not able to display this multimedia content.') .'

'; $output = _theme_video_format_play($output, t('http://www.macromedia.com/go/getflashplayer'), t('Link to Flash player download'), t('Download the latest Flash player')); return $output; } /** * Play Director .dcr/.dir files. * * @param $node * object with node information * * @return * string of content to display */ function theme_video_play_dcr($node) { $url = _video_get_fileurl($node->vidfile); // this will be executed by not Internet Explorer browsers $output = ' ' . "\n"; // this will be executed by Internet Explorer $output .= '' . "\n"; // params will be passed to both IE or not IE browsers $output .= '' . "\n" . _video_get_parameters($node) . '

'. t('Your browser is not able to display this multimedia content.') .'

'; $output = _theme_video_format_play($output, t('http://www.macromedia.com/shockwave/download/'), t('Link to Macromedia Shockwave Player Download Page'), t('Download latest Shockwave Player')); return $output; } /** * Play videos from in DivX format * * @see http://developer.apple.com/internet/ieembedprep.html * @param $node * object with node information * * @return * string of content to display */ function theme_video_play_divx($node) { //Increase the height to accommodate the player controls on the bottom. $height = $node->videoy + 20; $url = _video_get_fileurl($node->vidfile); $output = ' '. "\n"; // this will be executed by not Internet Explorer browsers $output = ' '."\n"; $output .= ''."\n"; $output .= ''."\n"; $output .= ''; $output = _theme_video_format_play($output,t('http://www.divx.com/divx/webplayer/'), t('Link to DivX Download Page'), t('Download latest DivX Web Player')); return $output; } /** * Play videos from in Quicktime format * * @see http://developer.apple.com/internet/ieembedprep.html * @param $node * object with node information * * @return * string of content to display */ function theme_video_play_quicktime($node) { //Increase the height to accommodate the player controls on the bottom. $height = $node->videoy + 16; $url = _video_get_fileurl($node->vidfile); // this will be executed by not Internet Explorer browsers $output = ' ' . "\n"; // this will be executed by Internet Explorer $output .= '' . "\n"; // params will be passed to both IE or not IE browsers $output .= ' ' . "\n" . _video_get_parameters($node) . '

'. t('Your browser is not able to display this multimedia content.') .'

'; // only one
needed becouse only one opening tag has been parsed by browsers /* $output = ''; */ $output = _theme_video_format_play($output, t('http://www.apple.com/quicktime/download'), t('Link to QuickTime Download Page'), t('Download latest Quicktime Player')); return $output; } /** * Play videos from in Realmedia format * * @param $node * object with node information * * @return * string of content to display */ function theme_video_play_realmedia($node) { // Real's embeded player includes the controls // in the height $node->videoy += 40; $url = _video_get_fileurl($node->vidfile); // this will be executed by not Internet Explorer browsers $output = ' ' . "\n"; // this will be executed by Internet Explorer $output .= '' . "\n"; // params will be passed to both IE or not IE browsers $output .= ' ' . _video_get_parameters($node) . '

'. t('Your browser is not able to display this multimedia content.') .'

'; // only one needed becouse only one opening tag has been parsed by browsers $output = _theme_video_format_play($output, t('http://www.real.com/'), t('Link to Real'), t('Download latest Realmedia Player')); return $output; } /** * Play videos from in WindowsMediaVideo format * * @param $node * object with node information * * @return * string of content to display */ function theme_video_play_windowsmedia($node) { // Windows Media's embeded player includes the controls in the height $node->videoy += 68; $url = _video_get_fileurl($node->vidfile); // this will be executed by not Internet Explorer browsers $output = ' ' . "\n"; // this will be executed by Internet Explorer $output .= '' . "\n"; // params will be passed to both IE or not IE browsers $output .= ' ' . _video_get_parameters($node) . '

'. t('Your browser is not able to display this multimedia content.') .'

'; // only one needed becouse only one opening tag has been parsed by browsers $output = _theme_video_format_play($output, t('http://windowsupdate.microsoft.com/'), t('Link to Windows Update'), t('Download latest Windows Media Player')); return $output; } /** * Play videos hosted on youtube.com * Allows users to host videos on youtube.com and then use the video ID to post it in the module. * In the future it could also use the youtube developer API to get info and comments of the video. * * @param $node * object with node information * * @return * string of content to display */ function theme_video_play_youtube($node) { $width = ($node->videox ? $node->videox : '425'); $height = ($node->videoy ? $node->videoy : '350'); // this will be executed by not Internet Explorer browsers $output = ' ' . "\n"; // this will be executed by Internet Explorer $output .= '' . "\n"; // params will be passed to both IE or not IE browsers $output .= '' . "\n" . _video_get_parameters($node) . '

'. t('Your browser is not able to display this multimedia content.') .'

'; $output = _theme_video_format_play($output, t('http://www.youtube.com/t/help_center'), t('Link to youtube.com'), t('youtube.com')); return $output; } /** * Play videos hosted on video.google.com * Allows users to host videos on video.google.com and then use the video ID to post it in the module. * * @param $node * object with node information * * @return * string of content to display */ function theme_video_play_googlevideo($node) { $width = ($node->videox ? $node->videox : '425'); $height = ($node->videoy ? $node->videoy : '350'); // Strip heading "google:" $videoid = substr($node->vidfile, 7); // this will be executed by not Internet Explorer browsers $output = ' ' . "\n"; // this will be executed by Internet Explorer $output .= '' . "\n"; // params will be passed to both IE or not IE browsers $output .= '' . "\n"; // following a list of params simply copied from old embed tag params. I don't know if this are really needed. $output .= ' ' . _video_get_parameters($node) . '

'. t('Your browser is not able to display this multimedia content.') .'

'; $output = _theme_video_format_play($output, t('http://video.google.com/support'), t('Link to video.google.com'), t('video.google.com')); return $output; } /** * Play Ogg Theora videos with Cortado Applet * * @param $node * object with node information * * @return * string of content to display */ function theme_video_play_ogg_theora($node) { global $base_url; $cortado_location = variable_get('video_cortado', $base_url . '/cortado.jar'); $url = _video_get_fileurl($node->vidfile); $width = ($node->videox ? $node->videox : '425'); $height = ($node->videoy ? $node->videoy : '350'); $output = ' This browser does not have a Java Plug-in.
Get the latest Java Plug-in here.
'; $output = _theme_video_format_play($output, t('http://java.com/download/'), t('Link to java.com'), t('Download Java')); return $output; } /** * Cut down on redundant link text * * @param $url * string URL to link to * * @param $title * string title of link to show on mouseover * * @param $link_text * string text of the link * * @return * string HTML link */ function _theme_video_format_play($output, $url, $title, $link_text) { $output = "\n
\n" . $output; $output .= "

\n". t('Problems viewing videos?'); $output .= "
\n"; $output .= l($link_text, $url, array('title' => $title), NULL, NULL, TRUE); return $output ."\n

\n
\n"; } /** * Takes an associative array of $fields with 'title' and 'body' keys and outputs the HTML. * This theme function allows the same HTML code to generate all the custom and metadata fields. * * @param $fields * array with 'title' and 'body' keys * * @return * string of content to display */ function theme_video_fields($fields) { $output = ''; $odd_even = 'odd'; foreach ($fields as $field) { $output .= "
" . check_plain($field['title']) . ' ' . check_plain($field['body']) . "
\n"; $odd_even = ($odd_even == 'odd') ? 'even' : 'odd'; //Always switch its value. } return $output; } /** * Import the video.js script */ function theme_video_get_script() { drupal_set_html_head(''); } /****************************************************************************** * End theme functions ****************************************************************************** * Start private functions created for this module. ******************************************************************************/ /** * Pull the file extension from a filename * * @param $vidfile * string filename to get the filetype from. * * @return * string value of file type or boolean FALSE on error */ function _video_get_filetype($vidfile) { //If the filename doesn't contain a ".", "/", or "\" and is exactly 11 characters then consider it a youtube video ID. if (!strpos($vidfile, '.') and !strpos($vidfile, '/') and !strpos($vidfile, '\\') and strlen($vidfile) == 11) { $file_type = 'youtube'; } else if (strpos($vidfile, 'google:') === 0) { $file_type = 'googlevideo'; } else if (strstr($vidfile, '.')) { //If file contains a "." then get the file extension after the "." $file_type = substr($vidfile, strrpos($vidfile, '.') + 1); } else { $file_type = FALSE; } return $file_type; } /** * Forward user directly to the file for downloading * * @param $input_url * string should be either a base64 encoded absolute URL, relative URL, or absolute URL. * * @param $vid * integer node version ID of the node to have it's download counter updated. * * @return * Nothing */ function _video_download_goto($input_url, $vid) { if (user_access('download video')) { $url = _video_get_fileurl($input_url); if (variable_get('video_downloadcounter', 1)) { db_query("UPDATE {video} SET download_counter = download_counter + 1 where vid = %d", $vid); //Increment download counter. } header("Location: $url"); //Redirect to the video files URL. } else { //If the user does not have access to download videos. drupal_set_message(t('You do not have permission to download videos.'), 'error'); $node = node_load(array('vid' => $vid)); //Load a node with the $vid so we can get the nid. drupal_goto("node/$node->nid"); //Use the nid we just loaded to go back to the node page. } } /** * Convert filesize to bytes * * @return * integer bytes */ function _video_size2bytes($node) { if (!empty($node->size)) { switch ($node->size_format) { case 'Kb': // KiloBits return intval($node->size * 128); break; case 'KB': // KiloBytes return intval($node->size * 1024); break; case 'Mb': // MegaBits return intval($node->size * 131072); break; case 'MB': // MegaBytes return intval($node->size * 1048576); break; case 'Gb': // GigaBits return intval($node->size * 134217728); break; case 'GB': // GigaBytes return intval($node->size * 1073741824); break; default: return (int)$node->size; break; } } else { return 0; } } /** * Convert seconds to hours, minutes, and seconds. * Derived from h:m:s example by Jon Haworth * * @link * http://www.laughing-buddha.net/jon/php/sec2hms/ * * @param $sec * integer value of seconds. * * @return * array associative with key values of hours, minutes, and seconds. */ function _video_sec2hms($sec = 0) { $hms = array(); // 3600 seconds in an hour and trash remainder $hms['hours'] = intval(intval($sec) / 3600); // dividing the total seconds by 60 will give us // the number of minutes, but we're interested in // minutes past the hour: to get that, we need to // divide by 60 again and keep the remainder $hms['minutes'] = intval(($sec / 60) % 60); $hms['seconds'] = intval($sec % 60); //keep the remainder. return $hms; } /** * Returns an absolute url which references * to the video file * * @param $video_file * string containing absolute or relative URL to video. * * @return * string containing absolute URL path to video file. */ function _video_get_fileurl($video_file) { global $base_url; //creation of absolute url if (preg_match("/^(http|ftp|mm|rstp)(s?):\/\//", $video_file)) { //If path is absolute return check_plain($video_file); } else { // path is relative to drupal install return check_plain($base_url . '/' . $video_file); } } /** * Returns the correct mime-type for the video. Returns false if the * mime-type cannot be detected. */ function _video_get_mime_type($node) { switch (_video_get_filetype($node->vidfile)) { case 'mov': return 'video/quicktime'; case 'divx': return 'video/vnd.divx'; case 'rm': return 'application/vnd.rn-realmedia'; case 'flv': return 'flv-application/octet-stream'; case 'wmv': return 'video/x-ms-wmv'; case '3gp': return 'video/3gpp'; case 'mp4': return 'video/mp4'; case 'dir': case 'dcr': return 'application/x-director'; // We can't support this sources properly, so return false. case 'youtube': case 'googlevideo': return false; case 'ogg': return 'application/ogg'; default: // We couldn't detect the mime-type, so return false. return false; } } /** * Generates the HTML for any object parameters in an embedded video. * * @param $node the node which is being played * * @return * string with the parameters in HTML form. */ function _video_get_parameters(&$node) { // call hook_v_get_params $param_value = module_invoke_all('v_get_params', $node); $output = ''; foreach ($param_value as $param => $value) { $output .= '\n'; } return $output; }