3
* $RCSfile: Getid3Helper.class,v $
5
* Gallery - a web based photo album viewer and editor
6
* Copyright (C) 2000-2006 Bharat Mediratta
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or (at
11
* your option) any later version.
13
* This program is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
23
* @version $Revision: 1.4 $ $Date: 2006/02/15 04:40:32 $
25
* @author Don Willingham <donwillingham@users.sf.net>
29
* Summary Getid3 setting
31
define('GETID3_SUMMARY', 1);
34
* Detailed Getid3 setting
36
define('GETID3_DETAILED', 2);
39
* Import mp3 title into item title
41
define('GETID3_MP3_TITLE', 1);
44
* A helper class for the Getid3 module.
52
* Reset the given view mode back to its default settings
54
* @param int the view mode
55
* @return object GalleryStatus a status code
58
function setDefaultProperties($viewMode) {
62
* This is an initial install. Make sure that we have some
63
* reasonable defaults.
65
$properties[] = 'Artist';
66
$properties[] = 'Album';
67
$properties[] = 'Track';
68
$properties[] = 'Title';
69
$properties[] = 'DateTime';
73
$properties[] = 'Artist';
74
$properties[] = 'Album';
75
$properties[] = 'Track';
76
$properties[] = 'Title';
77
$properties[] = 'Genre';
78
$properties[] = 'Year';
79
$properties[] = 'DateTime';
80
$properties[] = 'AudioBitRate';
81
$properties[] = 'AudioBitRateMode';
82
$properties[] = 'AudioChannels';
83
$properties[] = 'AudioCodec';
84
$properties[] = 'ChannelMode';
85
$properties[] = 'VideoBitRate';
86
$properties[] = 'VideoBitRateMode';
87
$properties[] = 'VideoCodec';
91
return GalleryStatus::error(ERROR_BAD_PARAMETER, __FILE__, __LINE__);
94
$ret = Getid3Helper::setProperties($viewMode, $properties);
96
return $ret->wrap(__FILE__, __LINE__);
103
* Return the raw data as returned by Getid3
105
* @param string the path to the file
106
* @param reference to an array where to store the results
107
* as returned by getid3()
109
function _fetchRawGetid3Data($path, &$rawGetid3Data) {
111
GalleryCoreApi::requireOnce('modules/getid3/lib/getid3/getid3.inc');
113
$platform =& $gallery->getPlatform();
114
if (!$platform->file_exists($path)) {
115
$rawGetid3Data = null;
119
$getID3 = new getID3;
120
$rawGetid3Data = $getID3->analyze($path);
123
function getId3ArchiveRecurse($results, $fileArray, $nameprefix='') {
124
foreach(array_keys($fileArray) as $filename) {
125
/* Only prepend a non-empty nameprefix and '/' to filename */
126
if ($nameprefix == '') {
127
$prefixedname = $filename;
129
$prefixedname = $nameprefix.'/'.$filename;
131
if (is_array($fileArray[$filename])) {
132
$results = Getid3Helper::getId3ArchiveRecurse(
133
$results, $fileArray[$filename], $prefixedname);
135
if (($nameprefix == '') || ($filename != 0) || ($fileArray[$filename] != 0)) {
136
$results[] = array('name' => $prefixedname, 'size' => $fileArray[$filename]);
143
function getId3ArchiveTar($fileDetails) {
145
foreach (array_keys($fileDetails) as $filename) {
146
if (is_array($fileDetails[$filename])) {
147
$results[] = array('name' => $filename,
148
'size' => $fileDetails[$filename]['size']);
154
function getId3ArchiveData($path, $viewMode) {
155
Getid3Helper::_fetchRawGetid3Data($path, $rawGetid3Data);
157
if (isset($rawGetid3Data['zip']['files'])) {
158
/* We must recurse through files array */
160
Getid3Helper::getId3ArchiveRecurse(array(), $rawGetid3Data['zip']['files'])));
162
if (isset($rawGetid3Data['iso']['files'])) {
163
/* Recurse through files like zip */
165
Getid3Helper::getId3ArchiveRecurse(array(), $rawGetid3Data['iso']['files'])));
167
if (isset($rawGetid3Data['tar']['file_details'])) {
168
/* getid3's tar output allows us to simply look, and not have to recurse */
170
Getid3Helper::getId3ArchiveTar($rawGetid3Data['tar']['file_details'])));
172
if (isset($rawGetid3Data['gzip']['member_header']['1']['tar']['file_details'])) {
173
/* tar-gzip is like tar, just buried a little deeper */
174
return(array(null, Getid3Helper::getId3ArchiveTar(
175
$rawGetid3Data['gzip']['member_header']['1']['tar']['file_details'])));
177
/* File probably isn't an archive */
178
return (array(null, null));
182
* Return the Getid3 data for a specific view and file
184
* @param string the path to the file
185
* @param int the view mode
186
* @return array object GalleryStatus a status code
187
* array title/value pairs
190
function getId3Data($path, $viewMode) {
191
Getid3Helper::_fetchRawGetid3Data($path, $rawGetid3Data);
192
$getid3Keys = Getid3Helper::getGetid3Keys();
195
list ($ret, $properties) = Getid3Helper::getProperties($viewMode);
197
return array($ret->wrap(__FILE__, __LINE__), null);
200
$errors = Getid3Helper::_getValue($rawGetid3Data, explode('.', 'error.0'));
201
if (isset($errors) && strlen($errors)) {
202
/* If there was an error, return nothing */
203
return array(null, array());
205
foreach ($properties as $property) {
206
$title = $getid3Keys[$property][0];
207
for ($i = 1; $i < count($getid3Keys[$property]); $i++) {
208
$value = Getid3Helper::_getValue(
209
$rawGetid3Data, explode('.', $getid3Keys[$property][$i]));
211
$value = Getid3Helper::postProcessValue($property, $value);
212
$results[] = array('title' => $title, 'value' => $value);
218
return array(null, $results);
222
* Return the timestamp of a time string in Day of week, Month, Day, Hour, Minute, Second,
225
* @param string time string
226
* @return int an unix timestamp, null if not parsed
228
function getTimeDowMDHMSY($value) {
229
/* Match "WED DEC 21 19:19:17 2005" format produced by a Canon SD400 */
230
if (preg_match('#(\w+)\ +(\w+)\ +(\d+)\ +(\d+):(\d+):(\d+)\ +(\d+)#', $value, $m)) {
233
case 'JAN': $month = 1; break;
234
case 'FEB': $month = 2; break;
235
case 'MAR': $month = 3; break;
236
case 'APR': $month = 4; break;
237
case 'MAY': $month = 5; break;
238
case 'JUN': $month = 6; break;
239
case 'JUL': $month = 7; break;
240
case 'AUG': $month = 8; break;
241
case 'SEP': $month = 9; break;
242
case 'OCT': $month = 10; break;
243
case 'NOV': $month = 11; break;
244
case 'DEC': $month = 12; break;
245
default: return null;
247
$time = mktime((int)$m[4], (int)$m[5], (int)$m[6],
248
$month, (int)$m[3], (int)$m[7]);
255
* Return the timestamp of a time string in Year, Month, Day, Hour, Minute, Second
258
* @param string time string
259
* @return int an unix timestamp, null if not parsed
261
function getTimeYMDHMS($value) {
263
* Match "2000:05:28 21:18:18" format produced by a
264
* TOSHIBA DIGITAL CAMERA PDRM70 VERSION 1.07
266
if (preg_match('#(\d+):(\d+):(\d+)\ +(\d+):(\d+):(\d+)#', $value, $m)) {
267
$time = mktime((int)$m[4], (int)$m[5], (int)$m[6],
268
(int)$m[2], (int)$m[3], (int)$m[1]);
275
* Return the timestamp of a time string already a time stamp.
277
* @param string time string
278
* @return int an unix timestamp, null if not parsed
280
function getTimeInt($value) {
281
if (preg_match('/^\d+$/', $value)) {
282
$time = intval($value);
283
/* Adjust time by time zone offset */
284
/* Get difference to UTC in seconds, then add to time */
285
$utcdiff = date('Z', $time);
286
$time = $time + $utcdiff;
294
* Sometimes the values that are returned aren't quite as we'd like to
295
* present them, so do a little post processing on the text
297
* @param string the property name (eg "ShutterSpeedValue")
298
* @param string the value (eg "25/10000 sec")
299
* @return string the result (eg "1/400 sec")
300
* @TODO(donw) Implement postProcessValue
302
function postProcessValue($property, $value) {
306
/* If it is already a timestamp, as a string */
307
$tmp = Getid3Helper::getTimeInt($value);
311
$tmp = Getid3Helper::getTimeDowMDHMSY($value);
315
$tmp = Getid3Helper::getTimeYMDHMS($value);
319
/* If we couldn't turn it into a timestamp, *
320
* then just use the original value */
326
list ($ret, $format) =
327
GalleryCoreApi::getPluginParameter('module', 'core', 'format.datetime');
328
if ($ret || empty($format)) {
331
$platform =& $gallery->getPlatform();
332
$value = $platform->strftime($format, $time);
339
* Return the timestamp when the item was taken, as recorded in exif, id3, or other meta tag
341
* @param string the path to the file
342
* @return int an unix timestamp
344
function getOriginationTimestamp($path) {
345
$rawGetid3Data = array();
346
Getid3Helper::_fetchRawGetid3Data($path, $rawGetid3Data);
348
array('riff.AVI .hdrl.IDIT.0.data',
349
'riff.AVI .INFO.IDIT.0.data',
350
'quicktime.moov.subatoms.0.creation_time_unix',
351
'quicktime.moov.subatoms.0.subatoms.1.subatoms.0.subatoms.0.creation_time_unix')
353
$value = Getid3Helper::_getValue($rawGetid3Data, explode('.', $tag));
355
$tmp = Getid3Helper::getTimeInt($value);
359
$tmp = Getid3Helper::getTimeDowMDHMSY($value);
363
$tmp = Getid3Helper::getTimeYMDHMS($value);
374
* Retrieve a single value by path from a nested associative array.
375
* The data source is an array like this:
378
* bar => (a => 1, b => 2, c => 3)
379
* baz => (d => 4, e => 5, f => 6)
381
* the key path is an array like this:
385
* the resulting value would be "4"
387
* @param array the data source
388
* @param array the key path
389
* @return array object GalleryStatus a status code
393
function _getValue(&$source, $keyPath) {
394
$key = array_shift($keyPath);
395
if (!isset($source[$key])) {
399
if (empty($keyPath)) {
400
return is_string($source[$key]) ? str_replace("\0", '', $source[$key]) : $source[$key];
402
return Getid3Helper::_getValue($source[$key], $keyPath);
407
* Return the target properties for the given view mode
409
* @param int the view mode (GETID3_SUMMARY, etc)
410
* @return array object GalleryStatus a status code
411
* array logical exif property names
414
function getProperties($viewMode) {
419
[Getid3PropsMap::property], [Getid3PropsMap::viewMode], [Getid3PropsMap::sequence]
423
[Getid3PropsMap::viewMode] = ?
425
[Getid3PropsMap::sequence] ASC';
426
list ($ret, $searchResults) = $gallery->search($query, array($viewMode));
428
return array($ret->wrap(__FILE__, __LINE__), null);
432
while ($result = $searchResults->nextResult()) {
433
$data[] = $result[0];
436
return array(null, $data);
440
* Set the target properties for the given view mode
442
* @param int the view mode (GETID3_SUMMARY, etc)
443
* @param array logical property key/value pairs
444
* @return object GalleryStatus a status code
447
function setProperties($viewMode, $properties) {
449
/* Remove all old map entries */
450
$ret = GalleryCoreApi::removeMapEntry('Getid3PropsMap', array('viewMode' => $viewMode));
452
return $ret->wrap(__FILE__, __LINE__);
455
for ($i = 0; $i < sizeof($properties); $i++) {
456
$ret = GalleryCoreApi::addMapEntry(
458
array('property' => $properties[$i],
459
'viewMode' => $viewMode,
462
return $ret->wrap(__FILE__, __LINE__);
471
* Return the Getid3 keys that we know about (from Getid3).
473
* The resulting array is of the form:
475
* logical getid3 property => (physical getid3 property, internationalized title, group)
476
* logical getid3 property => (physical getid3 property, internationalized title, group)
478
* The logical getid3 properties are unique and have some correlation to the
479
* physical property, but have been changed for our convenience. The physical
480
* getid3 property is the actual getid3 property name (as reported by Getid3). The group
481
* is an internationalized name of a group like "General Properties", etc.
483
* @return array getID3() keys
486
function getGetid3Keys() {
496
array($gallery->i18n('Album'),
497
'tags.vorbiscomment.album.0',
498
'tags.id3v1.album.0',
500
'id3v1.comments.album.0',
501
'tags_html.id3v1.album.0');
503
array($gallery->i18n('Artist'),
504
'tags.vorbiscomment.artist.0',
506
'tags.id3v1.artist.0',
508
'id3v1.comments.artist.0',
509
'tags_html.id3v1.artist.0');
510
$data['AudioBitRate'] =
511
array($gallery->i18n('Audio Bit Rate'),
513
'audio.streams.0.bitrate',
514
'mpeg.audio.bitrate',
516
$data['AudioBitRateMode'] =
517
array($gallery->i18n('Audio Bit Rate Mode'),
518
'audio.bitrate_mode',
519
'audio.streams.0.bitrate_mode',
520
'mpeg.audio.bitrate_mode');
521
$data['AudioChannels'] =
522
array($gallery->i18n('Audio Channels'),
524
'audio.streams.0.channels',
525
'mpeg.audio.channels');
526
$data['AudioCodec'] =
527
array($gallery->i18n('Audio Codec'),
530
$data['ChannelMode'] =
531
array($gallery->i18n('Channel Mode'),
532
'mpeg.audio.channelmode',
534
'audio.streams.0.channelmode');
535
$data['AudioSampleRate'] =
536
array($gallery->i18n('Audio Sample Rate'),
537
'audio.sample_rate');
539
array($gallery->i18n('Copyright'),
540
'comments.copyright',
541
'tags.quicktime.copyright');
543
array($gallery->i18n('Date/Time'),
544
'riff.AVI .hdrl.IDIT.0.data',
545
'riff.AVI .INFO.IDIT.0.data',
546
'quicktime.moov.subatoms.0.creation_time_unix',
547
'quicktime.moov.subatoms.0.subatoms.1.subatoms.0.subatoms.0.creation_time_unix');
549
array($gallery->i18n('Genre'),
550
'tags.vorbiscomment.genre.0',
552
'tags.id3v1.genre.0',
554
'id3v1.comments.genre',
555
'tags_html.id3v1.genre.0');
556
$data['PlaytimeSeconds'] =
557
array($gallery->i18n('Playtime (Seconds)'),
559
$data['PlaytimeString'] =
560
array($gallery->i18n('Playtime'),
563
array($gallery->i18n('Title'),
564
'tags.vorbiscomment.title.0',
566
'tags.id3v1.title.0',
568
'id3v1.comments.title.0',
569
'tags_html.id3v1.title.0',
571
'tags.quicktime.title');
573
array($gallery->i18n('Track'),
574
'tags.id3v1.track.0',
576
'id3v1.comments.track.0',
577
'tags_html.id3v1.track.0');
578
$data['VideoBitRate'] =
579
array($gallery->i18n('Video Bit Rate'),
581
$data['VideoBitRateMode'] =
582
array($gallery->i18n('Video Bit Rate Mode'),
583
'video.bitrate_mode');
584
$data['VideoCodec'] =
585
array($gallery->i18n('Video Codec'),
587
'quicktime.video.codec',
588
'riff.video.0.codec');
589
$data['VideoDataFormat'] =
590
array($gallery->i18n('Video Data Format'),
592
$data['VideoFrameRate'] =
593
array($gallery->i18n('Video Frame Rate'),
595
$data['VideoResolutionX'] =
596
array($gallery->i18n('Video Resolution X'),
597
'video.resolution_x');
598
$data['VideoResolutionY'] =
599
array($gallery->i18n('Video Resolution Y'),
600
'video.resolution_y');
601
$data['VideoSoftware'] =
602
array($gallery->i18n('Video Software'),
603
'riff.AVI .INFO.ISFT.0.data');
605
array($gallery->i18n('Year'),
608
'id3v1.comments.year.0',
609
'tags_html.id3v1.year.0');