You are here

video_multidownload.module in Video 5

Enable multiple file download in video module.

@author Fabio Varesano <fvaresano at yahoo dot it>

File

plugins/video_multidownload/video_multidownload.module
View source
<?php

/**
 * @file
 * Enable multiple file download in video module.
 *
 * @author Fabio Varesano <fvaresano at yahoo dot it>
 */

/**
 * Implementation of hook_help().
 */
function video_multidownload_help($section) {
  switch ($section) {
    case 'admin/modules#description':
      return t('Enable multiple file download in video module.');
  }
}

/**
 * Implementation of hook_menu().
 *
 * @param $may_cache
 *   boolean indicating whether cacheable menu items should be returned
 *
 * @return
 *   array of menu information
 */
function video_multidownload_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/content/video/multidownload',
      'title' => t('Multidownload'),
      'description' => t('Administer video_multidownload module settings'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'video_multidownload_settings_form',
      ),
      'access' => user_access('administer site configuration'),
      'type' => MENU_NORMAL_ITEM,
    );
  }
  else {
    if (arg(0) == 'node' && is_numeric(arg(1))) {
      if ($node = node_load(arg(1)) and $node->type == 'video') {
        if (isset($node->disable_multidownload) && !$node->disable_multidownload && ($node->use_play_folder || $node->download_folder != '')) {
          $items[] = array(
            'path' => 'node/' . arg(1) . '/multidownload',
            'title' => t('download other formats'),
            'callback' => 'video_multidownload_download',
            'access' => user_access('access video'),
            'weight' => 7,
            'type' => MENU_LOCAL_TASK,
          );
        }
      }
    }
  }
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function video_multidownload_perm() {
  return array(
    'create multi-file downloads',
  );
}

/**
 * Implementation of hook_settings()
 */
function video_multidownload_settings_form() {
  $form = array();
  $options = array(
    1 => 'Yes',
    0 => 'No',
  );
  $form['multifile'] = array(
    '#type' => 'fieldset',
    '#title' => t('Multi-file download options'),
    '#description' => t('Allows a list of files to be shown on the download page. The list is usually gotten from a specified folder. This ability is useful for providing different sizes and video types for download.'),
  );
  $form['multifile']['video_multidownload'] = array(
    '#type' => 'radios',
    '#title' => t('Allow Multi-file Downloads'),
    '#options' => $options,
    '#default_value' => variable_get('video_multidownload', 0),
    '#description' => t('This feature can be disabled separately for each node. If turned on make sure you set the permissions so users can use this feature.') . ' ' . l(t('access control'), 'admin/access'),
  );
  $form['multifile']['video_download_ext'] = array(
    '#type' => 'textfield',
    '#title' => t('File extensions to show'),
    '#default_value' => variable_get('video_download_ext', 'mov,wmv,rm,flv,avi,divx,mpg,mpeg,mp4,zip'),
    '#description' => t('The extensions of files to list from the multi-file download folder on the download page. Extensions should be comma seperated with no spaces, for example (mov,wmv,rm).'),
  );
  return system_settings_form($form);
}

/**
 * Implementation of hook_form_alter()
 * We use this to add multidownload fields to the video creation form.
 */
function video_multidownload_form_alter($form_id, &$form) {
  if ($form_id == 'video_node_form' && isset($form['video']) && user_access('create multi-file downloads')) {
    $node = $form['#node'];
    $form['multi-file'] = array(
      '#type' => 'fieldset',
      '#title' => t('Multiple files in download tab'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#weight' => -18,
      '#description' => t('These options allow you to have multiple files shown on the download page. This is useful for allowing users to download different file sizes and video formats. ') . l(t('More information.'), 'video/help', NULL, NULL, 'multi-download'),
    );
    $form['multi-file']['disable_multidownload'] = array(
      '#type' => 'checkbox',
      '#title' => t('Disable multi-file downloads'),
      '#default_value' => isset($node->disable_multidownload) ? $node->disable_multidownload : 1,
      '#description' => t('Disables multi-file downloads for this video only.'),
    );
    $form['multi-file']['download_folder'] = array(
      '#type' => 'textfield',
      '#title' => t('Multi-file download folder'),
      '#default_value' => $node->download_folder,
      '#maxlength' => 250,
      '#description' => t('Enter the folder containing your videos. It must be relative from the drupal directory. If the absolute path is "C:\\inetpub\\drupal\\videos\\projectfolder\\" or "/usr/htdocs/drupal/videos/projectfolder/" then enter something like "videos/projectfolder/".'),
    );
    $form['multi-file']['use_play_folder'] = array(
      '#type' => 'checkbox',
      '#title' => t('Show files in "play" folder'),
      '#default_value' => $node->use_play_folder,
      '#description' => t('Display videos in the same directory as the "play" video. If folder above is entered this will be in addition.'),
    );
  }
}

/**
 * Implementation of hook_nodeapi()
 */
function video_multidownload_nodeapi(&$node, $op, $teaser) {
  if ($node->type == 'video') {
    switch ($op) {
      case 'validate':

        //Validate multi-file download values.
        if (user_access('create multi-file downloads')) {

          //Make sure the user has permission.

          //Checks to make sure either multi-downloads are disabled, or a valid folder is given, or use_play_folder is checked.
          if ($node->disable_multidownload == 0 and !is_dir(getcwd() . '/' . $node->download_folder) and $node->use_play_folder == 0) {
            form_set_error('disable_multidownload', t("Please disable multi-file downloads if you are not going to use the feature."));
            form_set_error('download_folder', t('Download directory does not exist. Make sure it has a trailing forward slash "/".'));
          }
        }
        break;
    }
  }
}
function video_multidownload_download() {
  if ($node = node_load(arg(1))) {
    if (variable_get("video_multidownload", 0) == 0 or $node->disable_multidownload == 1) {
    }
    else {
      if (arg(3) != '') {

        //If we are passed an encoded URL redirect to the downloader.
        _video_multidownload_download_goto(arg(3), $node->vid, TRUE);
      }
      else {

        //Multiple file downloads is turned on.
        $download_error = FALSE;

        //Initialize and clear the error flag.
        $node->file_array = array();

        //Initialize the final file array.
        global $base_url;
        $full_download_folder = getcwd() . '/' . $node->download_folder;

        //Get absolute path to folder.

        //If the download folder is set and valid scan it for files.
        if ($node->download_folder != '' and file_exists($full_download_folder)) {
          $scan_download_folder = _video_multidownload_scandir($full_download_folder);

          //Get array of file names in the directory.
          $scan_download_folder['local_dir'] = $full_download_folder;

          //For getting filesize.
          $scan_download_folder['dir_stub'] = $node->download_folder;

          //To put in the URL.
          $folder_array[] = $scan_download_folder;
        }

        //If option is set to use "play" folder and it exists, scan it for files.
        $play_dir_stub = str_replace(basename($node->vidfile), "", $node->vidfile);

        //Remove the filename from the play file to get directory.
        $play_dir = getcwd() . '/' . $play_dir_stub;

        //Get the local directory path where the file is kept.
        if ($node->use_play_folder == 1 and file_exists($play_dir) and $play_dir_stub != '/') {

          //Make sure play stub won't allow scanning base drupal directory.
          $scan_play_folder = _video_multidownload_scandir($play_dir);
          $scan_play_folder['local_dir'] = $play_dir;

          //For getting filesize.
          $scan_play_folder['dir_stub'] = $play_dir_stub;

          //To put in the URL.
          $folder_array[] = $scan_play_folder;
        }
        if (count($folder_array) > 0) {

          //Make sure we have a folder to scan.
          foreach ($folder_array as $dir_scan) {

            //Scan through one or both folders results.
            foreach ($dir_scan as $file) {

              //Go through each file in the directory.
              if (is_file($dir_scan['local_dir'] . "/" . $file)) {

                //Make sure it's a valid file.

                //Checks the new file with the files already in the array to eliminate dupes.
                $match = false;
                foreach ($node->file_array as $file_array_file) {
                  if ($file_array_file['file'] == $file) {

                    //If the file is already in the array.
                    $match = TRUE;
                  }
                }

                //If we get here with $match still set FALSE we don't have a dupe.
                $file_ext = substr($file, strrpos($file, '.') + 1);

                //Get the file extension.
                $ext_array = explode(',', variable_get('video_download_ext', 'mov,wmv,avi'));
                if (!$match and in_array($file_ext, $ext_array)) {

                  //Only add file if it's not already in the array and it's extension shouldn't be hidden.
                  $file_array_size[] = filesize($dir_scan['local_dir'] . $file);

                  //Create an array of the file sizes for sorting.
                  global $base_url;
                  $file_url = $base_url . '/' . $dir_scan['dir_stub'] . $file;

                  //Generate absolute URL to video.
                  $file_url = str_replace(' ', '%20', $file_url);

                  //Replace any spaces in filename.
                  $encoded_url = base64_encode($file_url);

                  //Encode URL to base64 MIME value so it can be passed in URL.
                  $encoded_url = str_replace('/', '-', $encoded_url);

                  //Replace "/" with "-" so it doesn't mess up the URL.
                  $node->file_array[] = array(
                    'file' => $file,
                    'type' => $file_ext,
                    'size' => filesize($dir_scan['local_dir'] . $file),
                    'encoded_url' => $encoded_url,
                  );
                }
              }

              //Close the valid file check.
            }

            //Close the directory scan.
          }

          //Close scan location array.
          if (count($node->file_array) > 0) {

            //Make sure atleast 1 file was found.
            array_multisort($file_array_size, SORT_ASC, $node->file_array);

            //Sort based of file size.
          }
          else {

            //Else if no files were found in the directory.
            $download_error = TRUE;
          }
        }
        else {

          //Else if we have no valid folders to scan.
          $download_error = TRUE;
        }

        //If there was no error send the files array to the theme function for display.
        if ($download_error == FALSE) {
          print theme('video_multidownload_download', $node);

          //Print to the screen from the theme_video_download function.
        }
        else {

          //Else if there is an error download the play file.
          _video_download_goto($node->vidfile, $node->vid);
        }
      }
    }

    //Close multi-file downloads is turned on.
  }
}

/**
 * Outputs the HTML for the download page when multi-file download are turned on.
 *
 * @param $node
 *   object with node information
 *
 * @return
 *   string of content to display
 */
function theme_video_multidownload_download($node) {
  $output = '';

  //Replace some common file types with full name and links.
  $find = array(
    'mov',
    'wmv',
    'rm',
    'avi',
    'zip',
    'divx',
    'flv',
    'ogg',
  );
  $replace = array(
    '<a href="http://www.apple.com/quicktime" title="' . t('QuickTime Homepage') . '">' . t('Quicktime') . '</a>',
    '<a href="http://www.microsoft.com/windowsmedia" title="' . t('Windows Media Homepage') . '">' . t('Windows Media') . '</a>',
    '<a href="http://www.real.com" title="' . t('Real Media Homepage') . '">' . t('Real Media') . '</a>',
    '<a href="http://en.wikipedia.org/wiki/AVI" title="' . t('AVI Information at wikipedia.org') . '">' . t('AVI') . '</a>',
    '<a href="http://en.wikipedia.org/wiki/ZIP_file_format" title="' . t('ZIP Information at wikipedia.org') . '">' . t('ZIP') . '</a>',
    '<a href="http://www.divx.com" title="' . t('Divx Homepage') . '">' . t('DIVX') . '</a>',
    '<a href="http://www.macromedia.com/go/getflashplayer" title="' . t('Macromedia Flash Homepage') . '">' . t('Flash FLV') . '</a>',
    '<a href="http://www.theora.org/theorafaq.html" title="' . t('Ogg Theora FAQ at theora.org') . '">' . t('Ogg Theora FAQ') . '</a>, <a href="http://en.wikipedia.org/wiki/Wikipedia:Media_help_(Ogg)" title="' . t('Ogg Theora media help at Wikipedia') . '">' . t('Ogg Theora help') . '</a>',
  );
  $output .= '<br /><div class="videodownload">';

  //Enclose all HTML in "videodownload" class.
  foreach ($node->file_array as $file) {

    //Goes through the array of video files and gets them ready for display.
    $file_type = str_replace($find, $replace, $file['type']);

    //Match and replace common file types.
    $link = l($file['file'], "node/{$node->nid}/multidownload/" . $file['encoded_url']);

    //Create link to download file.
    $file_array_table[] = array(
      $link,
      format_size($file['size']),
      $file_type,
    );

    //Create table row.
  }
  $headers = array(
    t('File Link'),
    t('File Size'),
    t('File Type'),
  );
  $output .= theme_table($headers, $file_array_table);

  //Create the table of files.
  $output .= '</div>';

  //Close the "videodownload" class.

  //Adds a breadcrumb back to view on the download page. This may not be needed but some better breadcrumbs are.
  $breadcrumb = drupal_get_breadcrumb();
  $breadcrumb[] = l(t('View'), "node/{$node->nid}");
  drupal_set_breadcrumb($breadcrumb);
  drupal_set_title(t('Downloading') . ' ' . theme('placeholder', $node->title));
  return theme("page", $output);
}

/**
 * Scans a directory and returns an array of all the filenames in the directory.
 * This function is only necessary to maintain PHP 4 support.
 *
 * @param $dir
 *   The directory. Can be an absolute path or relative from the current working directory.
 *
 * @return
 *   array of filenames.
 */
function _video_multidownload_scandir($dir) {

  //Try a few different ways to open the directory.
  if (is_dir($dir)) {
    $dir_open = opendir($dir);
  }
  else {
    if (is_dir($new_dir = getcwd() . $dir)) {
      $dir_open = opendir($new_dir);
    }
    else {
      if (is_dir($new_dir = getcwd() . '/' . $dir)) {
        $dir_open = opendir($new_dir);
      }
      else {

        //If directory does not exist.
        return FALSE;
      }
    }
  }
  if (!$dir_open) {

    //If opendir returned false then return false.
    return FALSE;
  }

  //If it makes it this far $dir_open should be valid.
  while (($dir_content = readdir($dir_open)) !== FALSE) {
    $files[] = $dir_content;
  }
  return $files;
}

/**
 * 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.
 *
 * @param $base64_encoded
 *   boolean value determines whether the $input is base64 encoded.
 *
 * @return
 *   Nothing
 */
function _video_multidownload_download_goto($input_url, $vid, $base64_encoded) {
  if (user_access('download video') && $base64_encoded) {
    $encoded_url = str_replace('-', '/', $input_url);

    //Replace "-" to "/" for MIME base64.
    $location = base64_decode($encoded_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: {$location}");

    //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.
  }
}

Functions

Namesort descending Description
theme_video_multidownload_download Outputs the HTML for the download page when multi-file download are turned on.
video_multidownload_download
video_multidownload_form_alter Implementation of hook_form_alter() We use this to add multidownload fields to the video creation form.
video_multidownload_help Implementation of hook_help().
video_multidownload_menu Implementation of hook_menu().
video_multidownload_nodeapi Implementation of hook_nodeapi()
video_multidownload_perm Implementation of hook_perm().
video_multidownload_settings_form Implementation of hook_settings()
_video_multidownload_download_goto Forward user directly to the file for downloading
_video_multidownload_scandir Scans a directory and returns an array of all the filenames in the directory. This function is only necessary to maintain PHP 4 support.