Index: includes/filefield_meta.views.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield_meta/includes/filefield_meta.views.inc,v retrieving revision 1.2 diff -u -r1.2 filefield_meta.views.inc --- includes/filefield_meta.views.inc 24 Apr 2010 06:28:03 -0000 1.2 +++ includes/filefield_meta.views.inc 25 Apr 2010 05:10:58 -0000 @@ -162,6 +162,16 @@ ), ); + // Tags. + $data['filefield_meta']['tags'] = array( + 'title' => t('ID3 tags'), + 'help' => t('ID3 tags include embedded information such as artist, album, year, genre and other informaiton.'), + 'field' => array( + 'handler' => 'filefield_meta_handler_field_tags', + 'click sortable' => FALSE, + ), + ); + return $data; } @@ -184,6 +194,9 @@ 'filefield_meta_handler_field_samplerate' => array( 'parent' => 'views_handler_field_numeric', ), + 'filefield_meta_handler_field_tags' => array( + 'parent' => 'views_handler_field_prerender_list', + ), ), ); } Index: filefield_meta.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield_meta/filefield_meta.module,v retrieving revision 1.16 diff -u -r1.16 filefield_meta.module --- filefield_meta.module 24 Apr 2010 19:35:28 -0000 1.16 +++ filefield_meta.module 25 Apr 2010 05:10:58 -0000 @@ -1,5 +1,5 @@ fid); + $data = db_fetch_array($result); + + // Essentially this is a lazy-loader. If no record exists, read in the file. + if ($data) { + $data['tags'] = isset($data['tags']) ? unserialize($data['tags']) : array(); + $file->data = isset($file->data) ? array_merge($file->data, $data) : $data; + } + else { + filefield_meta_file_insert($file); + } +} + +/** + * Implementation of FileField's hook_file_insert(). */ function filefield_meta_file_insert(&$file) { if (!empty($file->fid)) { @@ -55,7 +82,7 @@ } /** - * Implementation of filefield's hook_file_update(). + * Implementation of FileField's hook_file_update(). */ function filefield_meta_file_update(&$file) { if (!empty($file->fid)) { @@ -65,7 +92,7 @@ } /** - * Implementation of filefield's hook_file_delete(). + * Implementation of FileField's hook_file_delete(). */ function filefield_meta_file_delete($file) { db_query('DELETE FROM {filefield_meta} WHERE fid = %d', $file->fid); @@ -77,6 +104,7 @@ function filefield_meta(&$file) { $info = getid3_analyze($file->filepath); + $file->data = isset($file->data) ? $file->data : array(); $file->data['width'] = $file->data['height'] = $file->data['duration'] = 0; if (isset($info['video']['resolution_x'])) { $file->data['width'] = $info['video']['resolution_x']; @@ -93,7 +121,7 @@ $file->data['duration'] = $info['playtime_seconds']; } - // initialize fields. + // Initialize fields. $file->data['audio_format'] = $file->data['audio_channel_mode'] = $file->data['audio_bitrate_mode'] = ''; $file->data['audio_sample_rate'] = $file->data['audio_bitrate'] = 0; @@ -104,7 +132,48 @@ $file->data['audio_bitrate'] = isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : NULL; //e.g. 64000 $file->data['audio_bitrate_mode'] = isset($info['audio']['bitrate_mode']) ? $info['audio']['bitrate_mode'] : NULL; //e.g. cbr } -}; + + // Add in arbitrary ID3 tags. + if (isset($info['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 ($info['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)) { + $file->data['tags'][$key] = html_entity_decode($value, ENT_QUOTES, 'UTF-8'); + } + } + } + } +} + +/** + * Utility function that simply returns the current list of all known ID3 tags. + * + * If new or different ID3 tags are desired, these may be overridden by adding + * the following to your site's settings.php file. + * + * @code + * $conf['filefield_meta_tags'] = array( + * 'title' => t('Title'), + * 'artist' => t('Artist'), + * 'composer' => t('Composer'), + * // etc... + * ); + * @endcode + */ +function filefield_meta_tags() { + $defaults = array( + 'title' => t('Title'), + 'artist' => t('Artist'), + 'album' => t('Album'), + 'year' => t('Year'), + 'genre' => t('Genre'), + ); + return variable_get('filefield_meta_tags', $defaults); +} /** * Convert the float duration into a pretty string. Index: filefield_meta.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield_meta/filefield_meta.install,v retrieving revision 1.8 diff -u -r1.8 filefield_meta.install --- filefield_meta.install 22 May 2009 21:14:52 -0000 1.8 +++ filefield_meta.install 25 Apr 2010 05:10:57 -0000 @@ -84,6 +84,11 @@ 'not null' => TRUE, 'default' => '', ), + 'tags' => array( + 'description' => 'ID3 tags such as artist, album, and genre.', + 'type' => 'text', + 'serialize' => TRUE, + ), ), 'primary key' => array('fid'), ); @@ -129,4 +134,36 @@ 'default' => '', )); return $ret; -} \ No newline at end of file +} + +/** + * Add the tags column. + */ +function filefield_meta_update_6100(&$context) { + $ret = array(); + + // Set up our update and add the tags column. + if (!isset($context['sandbox']['progress'])) { + $context['sandbox']['progress'] = 0; + $context['sandbox']['total'] = db_result(db_query("SELECT COUNT(*) FROM {files} f INNER JOIN {filefield_meta} fm ON f.fid = fm.fid WHERE fm.audio_format <> ''")); + $context['sandbox']['current_fid'] = 0; + + db_add_field($ret, 'filefield_meta', 'tags', array('type' => 'text')); + } + + // Select and process 200 files at a time. + $limit = 200; + $result = db_query_range("SELECT f.* FROM {files} f INNER JOIN {filefield_meta} fm ON f.fid = fm.fid WHERE f.fid > %d AND fm.audio_format <> '' ORDER BY f.fid ASC", $context['sandbox']['current_fid'], 0, $limit); + + // Loop through each file and read in its ID3 tags if applicable. + while ($file = db_fetch_object($result)) { + filefield_meta_file_update($file); + $context['sandbox']['current_fid'] = $file->fid; + $context['sandbox']['progress']++; + } + + // Update our progress indicator. + $ret['#finished'] = $context['sandbox']['progress'] / $context['sandbox']['total']; + + return $ret; +} Index: fielfield_meta.token.inc =================================================================== RCS file: fielfield_meta.token.inc diff -N fielfield_meta.token.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ fielfield_meta.token.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,60 @@ + $label) { + $tokens['file']['filefield-tag-' . $tag] = t('File ID3 @tag tag', array('@tag' => $label)); + } + + return $tokens; + } +} + +/** + * Implementation of hook_token_values(). + * + * Provide the token values for a given file item. + */ +function filefield_token_values($type, $object = NULL) { + $tokens = array(); + if ($type == 'field' && isset($object[0]['fid'])) { + $item = $object[0]; + + $tokens['filefield-width'] = $item['data']['width'] ; + $tokens['filefield-height'] = $item['data']['height'] ; + $tokens['filefield-duration'] = $item['data']['duration'] ; + $tokens['filefield-audio-format'] = isset($item['data']['audio_format']) ? $item['data']['audio_format'] : ''; + $tokens['filefield-audio-sample-rate'] = $item['data']['sample_rate'] ; + $tokens['filefield-audio-channel-mode'] = isset($item['data']['audio_channel_mode']) ? $item['data']['audio_channel_mode'] : ''; + $tokens['filefield-audio-bitrate'] = isset($item['data']['audio_bitrate']) ? $item['data']['audio_bitrate'] : ''; + $tokens['filefield-audio-bitrate-mode'] = isset($item['data']['audio_bitrate_mode']) ? $item['data']['audio_bitrate_mode'] : ''; + + // ID3 tags. + foreach (filefield_meta_tags() as $tag => $label) { + $tokens['filefield-tag-title'] = isset($item['data']['tags'][$tag]) ? $item['data']['tags'][$tag] : ''; + } + } + + return $tokens; +} Index: includes/filefield_meta_handler_field_tags.inc =================================================================== RCS file: includes/filefield_meta_handler_field_tags.inc diff -N includes/filefield_meta_handler_field_tags.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/filefield_meta_handler_field_tags.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,44 @@ + $default, 'required' => TRUE, 'translatable' => TRUE); + return $options; + } + + function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + + $form['relationship']['#weight'] = -2; + $form['tag'] = array( + '#type' => 'select', + '#title' => t('ID3 tag'), + '#required' => TRUE, + '#default_value' => $this->options['tag'], + '#options' => filefield_meta_tags(), + '#description' => t('Select the tag to be rendered. If needing multiple tags, add another ID3 tags field.'), + '#weight' => -1, + ); + } + + function render($values) { + $value = unserialize($values->{$this->field_alias}); + $tag = $this->options['tag']; + if (isset($value[$tag])) { + return check_plain($value[$tag]); + } + } +}