You are here

getid3.module in getID3() 7.2

Same filename and directory in other branches
  1. 8 getid3.module
  2. 5 getid3.module
  3. 6 getid3.module
  4. 7 getid3.module

File

getid3.module
View source
<?php

define('GETID3_RECOMMEND_VERSION', '1.8.2');

/**
 * Implements hook_help().
 */
function getid3_help($section, $arg) {
  switch ($section) {
    case 'admin/config/media/getid3':
      $help = '<p>' . t("To use this module you'll need to <a href='!download-link'>download the library</a> from the <a href='!info-link'>getID3 website</a> and extract the contents into the site's libraries directory. Currently, the recommended version of the getID3 library is %recommended-version.", array(
        '!download-link' => url('http://prdownloads.sourceforge.net/getid3'),
        '!info-link' => url('http://getid3.org/'),
        '%recommended-version' => GETID3_RECOMMEND_VERSION,
      )) . '</p>';
      return $help;
  }
}

/**
 * Implements hook_menu().
 */
function getid3_menu() {
  $items['admin/config/media/getid3'] = array(
    'title' => 'getID3()',
    'description' => 'Configure settings associated with getID3().',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'getid3_admin_settings_form',
      NULL,
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'file' => 'getid3.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_theme().
 */
function getid3_theme($existing, $type, $theme, $path) {
  return array(
    'getid3_duration' => array(
      'variables' => array(
        'duration' => NULL,
      ),
    ),
    'getid3_sample_rate' => array(
      'variables' => array(
        'sample_rate' => NULL,
      ),
    ),
    'getid3_bitrate' => array(
      'variables' => array(
        'bitrate' => NULL,
      ),
    ),
  );
}

/**
 * Implements hook_libraries_info().
 */
function getid3_libraries_info() {
  $libraries['getid3'] = array(
    'name' => 'getID3',
    'vendor url' => 'http://www.getid3.org',
    'download url' => 'http://sourceforge.net/projects/getid3/files/getID3%28%29%201.x/1.9.9/getID3-1.9.9-20141218.zip/download',
    'path' => 'getid3',
    'version' => '1.9.9',
    // @TODO: Move this into version_callback and version_arguments.
    'files' => array(
      'php' => array(
        'getid3.php',
      ),
    ),
  );
  return $libraries;
}

/**
 * Load the getID3 library.
 *
 * @return
 *   Boolean indicating if the library was successfully loaded.
 */
function getid3_load($display_warning = TRUE) {

  // Ensure the getID3() library is loaded.
  $library = libraries_detect('getid3');
  if ($library['installed']) {
    libraries_load('getid3');
    return TRUE;
  }
  return FALSE;
}

/**
 * Create and initialize an instance of getID3 class.
 */
function getid3_instance() {
  $id3 = NULL;
  if (getid3_load()) {
    $id3 = new getID3();

    // MD5 is a big performance hit. Disable it by default.
    $id3->option_md5_data = FALSE;
    $id3->option_md5_data_source = FALSE;
    $id3->encoding = 'UTF-8';
  }
  return $id3;
}
function getid3_calc($word) {
  $m = 1;
  $int = 0;
  for ($i = strlen($word) - 1; $i > -1; $i--) {
    $int += $m * ord($word[$i]);
    $m = $m * 128;
  }
  return $int;
}

/**
 * Takes a file entity object and returns ID3 data.
 * @param $file
 * @return null|array
 */
function getid3_analyze_file($file) {

  // Initialize
  $getID3 = getid3_instance();
  $file_realpath = drupal_realpath($file->uri);

  // Verify file exists, as external files are saved as managed files
  // Ex: this prevents errors on media_youtube or media_vimeo entries.
  if (file_exists($file_realpath)) {

    // Analyze.
    return $getID3
      ->analyze($file_realpath);
  }

  // If the file path isn't local
  if ($file_realpath === FALSE) {
    $file_urlpath = file_create_url($file->uri);
    $tmp = file_directory_temp() . '/' . $file->filename;
    if (file_put_contents($tmp, file_get_contents($file_urlpath, false, null, 0, 10))) {
      $tagLen = getid3_calc(substr($tmp, 6, 4));
      unlink($tmp);
      file_put_contents($tmp, file_get_contents($file_urlpath, false, null, 0, $tagLen));
      return $getID3
        ->analyze($tmp);
    }
  }
  return NULL;
}

/**
 * Implements hook_file_presave().
 */
function getid3_file_presave($file) {

  // Make sure we do not try to extract ID3 data from non valid types.
  if (!in_array($file->type, array(
    'video',
    'audio',
  ))) {
    return null;
  }

  // Load the ID3 data.
  $id3_data = getid3_analyze_file($file);

  // If we have data, attach it to metadata.
  if ($id3_data) {

    // Set the duration
    if (isset($id3_data['playtime_string'])) {
      $file->metadata['duration'] = $id3_data['playtime_string'];
    }

    // Update video specific information.
    if (isset($id3_data['video'])) {
      $file->metadata['width'] = $id3_data['video']['resolution_x'];
      $file->metadata['height'] = $id3_data['video']['resolution_y'];
    }

    // Update audio specific information.
    if (isset($id3_data['audio'])) {
      $file->metadata['audio_format'] = $id3_data['audio']['dataformat'];
      $file->metadata['audio_sample_rate'] = $id3_data['audio']['sample_rate'];
      $file->metadata['audio_channel_mode'] = $id3_data['audio']['channelmode'];
      $file->metadata['audio_bitrate'] = isset($id3_data['audio']['bitrate']) ? $id3_data['audio']['bitrate'] : NULL;
      $file->metadata['audio_bitrate_mode'] = isset($id3_data['audio']['bitrate_mode']) ? $id3_data['audio']['bitrate_mode'] : NULL;
    }
  }

  // @TODO: Kill off the audio module by allowing users to edit id3 tags on
  // files. Explore a sub-module that allows tags to be mapped to CCK fields and
  // allows reading and writing of the tags.
  // Add in arbitrary ID3 tags.
  if (isset($id3_data['tags_html'])) {

    // We use tags_html instead of tags because it is the most reliable data
    // source for pulling in non-UTF-8 characters according to getID3 docs.
    foreach ($id3_data['tags_html'] as $type => $values) {

      // Typically $type may be IDv2 (for MP3s) or quicktime (for AAC).
      foreach ($values as $key => $value) {
        $value = isset($value[0]) ? (string) $value[0] : (string) $value;
        if (!empty($value) && $key != 'coverart') {
          $file->metadata['tags'][$key] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
        }
      }
    }
  }
}

/**
 * Triggers the batch operation for updating file entities.
 */
function getid3_perform_batch_process() {
  $batch = array(
    'title' => t('Updating existing File Entities with ID3 data'),
    'init_message' => t('Preparing to update entities..'),
    'progress_message' => t('Processed @current out of @total items.'),
    'operations' => array(
      array(
        'getid3_analyze_existing_files',
        array(),
      ),
    ),
    'finished' => 'getid3_perform_batch_process_complete',
  );
  batch_set($batch);
}

/**
 * BatchAPI complete callback for getID3 import.
 */
function getid3_perform_batch_process_complete($success, $results, $operations) {
  if ($success) {
    drupal_set_message(t('File entity ID3 data updated @count files successfully.', array(
      '@count' => count($results),
    )));
  }
  else {
    drupal_set_message(theme('item_list', array(
      'items' => $results['errors'],
    )), 'error');
  }
}

/**
 * Performs batch operations to update existing file entity metadata.
 *
 * @param $context
 * @return null|string
 */
function getid3_analyze_existing_files(&$context) {

  // Little workaround so update hook and can use same batch.
  if (isset($context['sandbox'])) {
    $sandbox =& $context['sandbox'];
  }
  else {
    $sandbox =& $context;
  }

  // Lets update 10 files at a time.
  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['current_fid'] = 0;

    // We only select files that are not in the getid3_meta table.
    $sandbox['max'] = db_query('SELECT COUNT(fid) FROM {file_managed} f WHERE f.filemime LIKE :video OR f.filemime LIKE :audio', array(
      ':video' => 'video%',
      ':audio' => 'audio%',
    ))
      ->fetchField();
  }
  $query = db_select('file_managed', 'f')
    ->fields('f', array(
    'fid',
  ))
    ->condition('fid', $sandbox['current_fid'], '>')
    ->range(0, 10)
    ->orderBy('fid', 'ASC');
  $db_or = db_or();
  $db_or
    ->condition('f.filemime', db_like('video') . '%', 'LIKE');
  $db_or
    ->condition('f.filemime', db_like('audio') . '%', 'LIKE');
  $query
    ->condition($db_or);
  $files = $query
    ->execute()
    ->fetchAll();
  foreach ($files as $file) {

    // We just need to re-save entities.
    $file = file_load($file->fid);
    file_save($file);

    // Update batch
    $sandbox['progress']++;
    $context['results'][] = $file->fid;
    $sandbox['current_fid'] = $file->fid;
  }
  $context['message'] = t('Parsing @current out of @max files', array(
    '@current' => count($context['results']),
    '@max' => $sandbox['max'],
  ));

  // Let Batch API or upgrade hook know if this batch set is completed.
  $context['finished'] = empty($sandbox['max']) ? 1 : $sandbox['progress'] / $sandbox['max'];
  $sandbox['#finished'] = $context['finished'];
}

/**
 * Implements hook_views_api().
 */
function getid3_views_api() {
  return array(
    'api' => 3.0,
    'path' => drupal_get_path('module', 'getid3') . '/includes',
  );
}

/**
 * Format a float duration into minutes:seconds.
 *
 * @param $variables
 *   Array with 'duration' key.
 */
function theme_getid3_duration($variables) {
  $duration = $variables['duration'];
  $seconds = round(($duration / 60 - floor($duration / 60)) * 60);
  $minutes = floor($duration / 60);
  if ($seconds >= 60) {
    $seconds -= 60;
    $minutes++;
  }
  return (int) $minutes . ':' . str_pad($seconds, 2, 0, STR_PAD_LEFT);
}

/**
 * Format an audio sample rate.
 *
 * @param $variables
 *   Array with 'sample_rate' key.
 */
function theme_getid3_sample_rate($variables) {
  return t('@sampleratekHz', array(
    '@samplerate' => (int) ($variables['sample_rate'] / 1000),
  ));
}

/**
 * Format an audio bitrate.
 *
 * @param $variables
 *   Array with 'bitrate' key.
 */
function theme_getid3_bitrate($variables) {
  return t('@bitrateKbps', array(
    '@bitrate' => (int) ($variables['bitrate'] / 1000),
  ));
}

Functions

Namesort descending Description
getid3_analyze_existing_files Performs batch operations to update existing file entity metadata.
getid3_analyze_file Takes a file entity object and returns ID3 data.
getid3_calc
getid3_file_presave Implements hook_file_presave().
getid3_help Implements hook_help().
getid3_instance Create and initialize an instance of getID3 class.
getid3_libraries_info Implements hook_libraries_info().
getid3_load Load the getID3 library.
getid3_menu Implements hook_menu().
getid3_perform_batch_process Triggers the batch operation for updating file entities.
getid3_perform_batch_process_complete BatchAPI complete callback for getID3 import.
getid3_theme Implements hook_theme().
getid3_views_api Implements hook_views_api().
theme_getid3_bitrate Format an audio bitrate.
theme_getid3_duration Format a float duration into minutes:seconds.
theme_getid3_sample_rate Format an audio sample rate.

Constants