source: trunk/SapphireMetaData.m @ 57

Revision 57, 19.4 KB checked in by gbooker, 7 years ago (diff)

Predicate matching for watched/favorite marking and display

Line 
1//
2//  SapphireMetaData.m
3//  Sapphire
4//
5//  Created by Graham Booker on 6/22/07.
6//  Copyright 2007 __MyCompanyName__. All rights reserved.
7//
8
9#import "SapphireMetaData.h"
10#import <QTKit/QTKit.h>
11
12//Structure Specific Keys
13#define FILES_KEY                                       @"Files"
14#define DIRS_KEY                                        @"Dirs"
15#define META_VERSION_KEY                        @"Version"
16#define META_VERSION                            1
17
18//File Specific Keys
19#define MODIFIED_KEY                    @"Modified"
20#define WATCHED_KEY                             @"Watched"
21#define FAVORITE_KEY                    @"Favorite"
22#define RESUME_KEY                              @"Resume Time"
23#define SIZE_KEY                                @"Size"
24#define DURATION_KEY                    @"Duration"
25#define AUDIO_DESC_KEY                  @"Audio Description"
26#define SAMPLE_RATE_KEY                 @"Sample Rate"
27#define VIDEO_DESC_KEY                  @"Video Description"
28
29//TV Show Specific Keys
30#define EPISODE_NUMBER_KEY              @"Episode Number"
31#define EPISODE_TITLE_KEY               @"Episode Title"
32#define SEASON_NUMBER_KEY               @"Season"
33#define SHOW_NAME_KEY                   @"Show Name"
34#define SHOW_DESCRIPTION_KEY    @"Show Description"
35#define SHOW_AIR_DATE                   @"Air Date"
36
37
38@implementation NSString (episodeSorting)
39
40// Custom TV Episode handler
41- (NSComparisonResult) episodeCompare:(NSString *)other
42{
43        return [self compare:other options:NSCaseInsensitiveSearch | NSNumericSearch];
44}
45
46@end
47
48@implementation SapphireMetaData
49
50// Static set of file extensions to filter
51static NSArray *extensions = nil;
52
53+(void)load
54{
55        extensions = [[NSArray alloc] initWithObjects:@"avi", @"mov", @"mpg", @"wmv",@"mkv", @"flv", @"divx", @"mp4", nil];
56}
57
58- (id)initWithDictionary:(NSDictionary *)dict parent:(SapphireMetaData *)myParent path:(NSString *)myPath
59{
60        self = [super init];
61        if(!self)
62                return nil;
63       
64        if(dict == nil)
65                metaData = [NSMutableDictionary new];
66        else
67                metaData = [dict mutableCopy];
68        path = [myPath retain];
69        parent = myParent;
70       
71        return self;
72}
73
74- (void)dealloc
75{
76        [metaData release];
77        [path release];
78        [super dealloc];
79}
80
81- (NSMutableDictionary *)dict
82{
83        return metaData;
84}
85
86- (NSString *)path
87{
88        return path;
89}
90
91- (void)setDelegate:(id <SapphireMetaDataDelegate>)newDelegate
92{
93        delegate = newDelegate;
94}
95
96- (void)writeMetaData
97{
98        [parent writeMetaData];
99}
100
101- (BOOL)isDirectory:(NSString *)fullPath
102{
103        BOOL isDir = NO;
104        return [[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDir] && isDir;
105}
106
107@end
108
109@implementation SapphireMetaDataCollection
110
111- (id)initWithFile:(NSString *)dictionary path:(NSString *)myPath
112{
113        self = [super init];
114        if(!self)
115                return nil;
116       
117        dictionaryPath = [dictionary retain];
118        NSDictionary *metaDict = [NSDictionary dictionaryWithContentsOfFile:dictionary];
119        mainDirectory = [[SapphireDirectoryMetaData alloc] initWithDictionary:metaDict parent:self path:myPath];
120        metaData = [[mainDirectory dict] retain];
121        [metaData setObject:[NSNumber numberWithInt:META_VERSION] forKey:META_VERSION_KEY];
122       
123        return self;
124}
125
126- (void)dealloc
127{
128        [mainDirectory release];
129        [dictionaryPath release];
130        [super dealloc];
131}
132
133- (SapphireDirectoryMetaData *)rootDirectory
134{
135        return mainDirectory;
136}
137
138static void makeParentDir(NSFileManager *manager, NSString *dir)
139{
140        NSString *parent = [dir stringByDeletingLastPathComponent];
141       
142        BOOL isDir;
143        if(![manager fileExistsAtPath:parent isDirectory:&isDir])
144                makeParentDir(manager, parent);
145        else if(!isDir)
146                //Can't work with this
147                return;
148       
149        [manager createDirectoryAtPath:dir attributes:nil];
150}
151
152- (void)writeMetaData
153{
154        makeParentDir([NSFileManager defaultManager], [dictionaryPath stringByDeletingLastPathComponent]);
155        [[mainDirectory dict] writeToFile:dictionaryPath atomically:YES];
156}
157
158@end
159
160@interface SapphireDirectoryMetaData (private)
161- (void)reloadDirectoryContents;
162@end
163
164@implementation SapphireDirectoryMetaData
165
166- (id)initWithDictionary:(NSDictionary *)dict parent:(SapphireMetaData *)myParent path:(NSString *)myPath
167{
168        self = [super initWithDictionary:dict parent:myParent path:myPath];
169        if(!self)
170                return nil;
171       
172        metaFiles = [metaData objectForKey:FILES_KEY];
173        if(metaFiles == nil)
174                metaFiles = [NSMutableDictionary new];
175        else
176                metaFiles = [metaFiles mutableCopy];
177        [metaData setObject:metaFiles forKey:FILES_KEY];
178        [metaFiles release];
179
180        metaDirs = [metaData objectForKey:DIRS_KEY];
181        if(metaDirs == nil)
182                metaDirs = [NSMutableDictionary new];
183        else
184                metaDirs = [metaDirs mutableCopy];
185        [metaData setObject:metaDirs forKey:DIRS_KEY];
186        [metaDirs release];
187       
188        cachedMetaDirs = [NSMutableDictionary new];
189        cachedMetaFiles = [NSMutableDictionary new];
190       
191        return self;
192}
193
194- (void)dealloc
195{
196        [importTimer invalidate];
197        [importArray release];
198        [cachedMetaDirs release];
199        [cachedMetaFiles release];
200        [files release];
201        [directories release];
202        [super dealloc];
203}
204
205- (void)reloadDirectoryContents
206{
207        [files release];
208        [directories release];
209        files = [NSMutableArray new];
210        directories = [NSMutableArray new];
211       
212        NSArray *names = [[NSFileManager defaultManager] directoryContentsAtPath:path];
213       
214        NSEnumerator *nameEnum = [names objectEnumerator];
215        NSString *name = nil;
216        // Display Menu Items
217        while((name = [nameEnum nextObject]) != nil)
218        {
219                if([name hasPrefix:@"."])
220                        continue;
221                //Only accept if it is a directory or right extension
222                NSString *extension = [name pathExtension];
223                if([self isDirectory:[path stringByAppendingPathComponent:name]])
224                        [directories addObject:name];
225                else if([extensions containsObject:extension])
226                        [files addObject:name];
227        }
228        [directories sortUsingSelector:@selector(episodeCompare:)];
229        [files sortUsingSelector:@selector(episodeCompare:)];
230        [self updateMetaData];
231}
232
233- (NSArray *)files
234{
235        return files;
236}
237
238- (NSArray *)directories
239{
240        return directories;
241}
242
243- (BOOL)hasPredicatedFiles:(SapphirePredicate *)predicate
244{
245        NSEnumerator *fileEnum = [files objectEnumerator];
246        NSString *file = nil;
247        while((file = [fileEnum nextObject]) != nil)
248        {
249                BOOL include = NO;
250                if([metaFiles objectForKey:file] != nil)
251                {
252                        SapphireFileMetaData *meta = [self metaDataForFile:file];
253                        include = [predicate accept:[meta path] meta:meta];
254                }
255                else
256                        include = [predicate accept:[path stringByAppendingPathComponent:file] meta:nil];
257                if(include)
258                        return YES;
259        }
260        return NO;
261}
262
263- (BOOL)hasPredicatedDirectories:(SapphirePredicate *)predicate
264{
265        NSEnumerator *directoryEnum = [directories objectEnumerator];
266        NSString *directory = nil;
267        while((directory = [directoryEnum nextObject]) != nil)
268        {
269                SapphireDirectoryMetaData *meta = [self metaDataForDirectory:directory];
270                [meta cancelImport];
271               
272                if([meta hasPredicatedFiles:predicate] || [meta hasPredicatedDirectories:predicate])
273                        return YES;
274        }
275        return NO;
276}
277
278- (NSArray *)predicatedFiles:(SapphirePredicate *)predicate
279{
280        NSMutableArray *ret = [NSMutableArray array];
281        NSEnumerator *fileEnum = [files objectEnumerator];
282        NSString *file = nil;
283        while((file = [fileEnum nextObject]) != nil)
284        {
285                BOOL include = NO;
286                if([metaFiles objectForKey:file] != nil)
287                {
288                        SapphireFileMetaData *meta = [self metaDataForFile:file];
289                        include = [predicate accept:[meta path] meta:meta];
290                }
291                else
292                        include = [predicate accept:[path stringByAppendingPathComponent:file] meta:nil];
293                if(include)
294                        [ret addObject:file];
295        }
296        return ret;
297}
298- (NSArray *)predicatedDirectories:(SapphirePredicate *)predicate
299{
300        NSMutableArray *ret = [NSMutableArray array];
301        NSEnumerator *directoryEnum = [directories objectEnumerator];
302        NSString *directory = nil;
303        while((directory = [directoryEnum nextObject]) != nil)
304        {
305                SapphireDirectoryMetaData *meta = [self metaDataForDirectory:directory];
306                [meta reloadDirectoryContents];
307
308                if([meta hasPredicatedFiles:predicate] || [meta hasPredicatedDirectories:predicate])
309                        [ret addObject:directory];
310        }
311        return ret;
312}
313
314- (SapphireFileMetaData *)metaDataForFile:(NSString *)file
315{
316        SapphireFileMetaData *ret = [cachedMetaFiles objectForKey:file];
317        if(ret == nil)
318        {
319                ret = [[SapphireFileMetaData alloc] initWithDictionary:[metaFiles objectForKey:file] parent:self path:[path stringByAppendingPathComponent:file]];
320                [metaFiles setObject:[ret dict] forKey:file];
321                [cachedMetaFiles setObject:ret forKey:file];
322                [ret autorelease];
323        }
324        return ret;
325}
326
327- (SapphireDirectoryMetaData *)metaDataForDirectory:(NSString *)file
328{
329        SapphireDirectoryMetaData *ret = [cachedMetaDirs objectForKey:file];
330        if(ret == nil)
331        {
332                ret = [[SapphireDirectoryMetaData alloc] initWithDictionary:[metaDirs objectForKey:file] parent:self path:[path stringByAppendingPathComponent:file]];
333                [metaDirs setObject:[ret dict] forKey:file];
334                [cachedMetaDirs setObject:ret forKey:file];
335                [ret autorelease];             
336        }
337        return ret;
338}
339
340- (BOOL)pruneMetaData
341{
342        BOOL ret = NO;
343        NSSet *existingSet = [NSSet setWithArray:files];
344        NSArray *metaArray = [metaFiles allKeys];
345        NSMutableSet *pruneSet = [NSMutableSet setWithArray:metaArray];
346       
347        [pruneSet minusSet:existingSet];
348        if([pruneSet anyObject] != nil)
349        {
350                NSEnumerator *pruneEnum = [pruneSet objectEnumerator];
351                NSString *pruneKey = nil;
352                while((pruneKey = [pruneEnum nextObject]) != nil)
353                        [metaFiles removeObjectForKey:pruneKey];
354                ret = YES;             
355        }
356       
357        existingSet = [NSSet setWithArray:directories];
358        metaArray = [metaDirs allKeys];
359        pruneSet = [NSMutableSet setWithArray:metaArray];
360       
361        [pruneSet minusSet:existingSet];
362        if([pruneSet anyObject] != nil)
363        {
364                NSEnumerator *pruneEnum = [pruneSet objectEnumerator];
365                NSString *pruneKey = nil;
366                while((pruneKey = [pruneEnum nextObject]) != nil)
367                        [metaDirs removeObjectForKey:pruneKey];
368                ret = YES;
369        }
370       
371        return ret;
372}
373
374- (BOOL)updateMetaData
375{
376        NSEnumerator *fileEnum = [files objectEnumerator];
377        NSString *fileName = nil;
378        importArray = [[NSMutableArray alloc] init];
379        while((fileName = [fileEnum nextObject]) != nil)
380        {
381                NSDictionary *fileMeta = [metaFiles objectForKey:fileName];
382                if(fileMeta == nil)
383                        [importArray addObject:fileName];
384                else
385                {
386                        NSString *filePath = [path stringByAppendingPathComponent:fileName];
387                        NSDictionary *props = [[NSFileManager defaultManager] fileAttributesAtPath:filePath traverseLink:YES];
388                        NSDate *modDate = [props objectForKey:NSFileModificationDate];
389                        if([[fileMeta objectForKey:MODIFIED_KEY] intValue] != [modDate timeIntervalSince1970] || [[fileMeta objectForKey:META_VERSION_KEY] intValue] != META_VERSION)
390                                [importArray addObject:fileName];
391                }
392        }
393        return NO;
394}
395
396- (void)processFiles:(NSTimer *)timer
397{
398        NSString *file = [importArray objectAtIndex:0];
399       
400        [[self metaDataForFile:file] updateMetaData];
401       
402        [self writeMetaData];
403        [delegate updateComplete];
404       
405        [importArray removeObjectAtIndex:0];
406        [self resumeImport];
407}
408
409- (void)cancelImport
410{
411        [importTimer invalidate];
412        importTimer = nil;
413}
414
415- (void)resumeImport
416{
417        [importTimer invalidate];
418        if([importArray count])
419                importTimer = [NSTimer scheduledTimerWithTimeInterval:1.1 target:self selector:@selector(processFiles:) userInfo:nil repeats:NO];
420        else
421        {
422                [importTimer invalidate];
423                importTimer = nil;
424                [importArray release];
425                importArray = nil;
426        }
427}
428
429- (void)resumeDelayedImport
430{
431        [importTimer invalidate];
432        if([importArray count])
433                importTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(resumeImport) userInfo:nil repeats:NO];
434}
435
436- (SapphireMetaData *)metaDataForSubPath:(NSString *)subPath
437{
438        NSArray *components = [subPath pathComponents];
439        if(![components count])
440                return self;
441        NSString *file = [components objectAtIndex:0];
442       
443        if([self isDirectory:[path stringByAppendingPathComponent:file]])
444        {
445                NSMutableArray *newComp = [components mutableCopy];
446                [newComp removeObjectAtIndex:0];
447                [newComp autorelease];
448                SapphireDirectoryMetaData *nextLevel = [self metaDataForDirectory:file];
449                return [nextLevel metaDataForSubPath:[NSString pathWithComponents:newComp]];
450        }
451        else if([components count] > 1)
452                return nil;
453        return [self metaDataForFile:file];
454}
455
456- (NSArray *)subFileMetas
457{
458        NSMutableArray *ret = [[NSMutableArray alloc] init];
459        [self reloadDirectoryContents];
460        NSEnumerator *dirEnum = [directories objectEnumerator];
461        NSString *dir = nil;
462        while((dir = [dirEnum nextObject]) != nil)
463        {
464                SapphireDirectoryMetaData *dirMeta = [self metaDataForDirectory:dir];
465                if(dirMeta != nil)
466                        [ret addObjectsFromArray:[dirMeta subFileMetas]];
467        }
468        NSEnumerator *fileEnum = [files objectEnumerator];
469        NSString *file = nil;
470        while((file = [fileEnum nextObject]) != nil)
471        {
472                SapphireFileMetaData *fileMeta = [self metaDataForFile:file];
473                if(fileMeta != nil)
474                        [ret addObject:fileMeta];
475        }
476        return [ret autorelease];
477}
478
479- (BOOL)watchedForPredicate:(SapphirePredicate *)predicate
480{
481        NSArray *filesToScan = files;
482        NSArray *directoriesToScan = directories;
483        if(predicate)
484        {
485                filesToScan = [self predicatedFiles:predicate];
486                directoriesToScan = [self predicatedDirectories:predicate];
487        }
488        NSEnumerator *fileEnum = [filesToScan objectEnumerator];
489        NSString *file = nil;
490        while((file = [fileEnum nextObject]) != nil)
491                if(![[self metaDataForFile:file] watched])
492                        return NO;
493
494        NSEnumerator *dirEnum = [directoriesToScan objectEnumerator];
495        NSString *dir = nil;
496        while((dir = [dirEnum nextObject]) != nil)
497                if(![[self metaDataForDirectory:dir] watchedForPredicate:predicate])
498                        return NO;
499
500        return YES;
501}
502
503- (void)setWatched:(BOOL)watched predicate:(SapphirePredicate *)predicate
504{
505        NSArray *filesToScan = files;
506        NSArray *directoriesToScan = directories;
507        if(predicate)
508        {
509                filesToScan = [self predicatedFiles:predicate];
510                directoriesToScan = [self predicatedDirectories:predicate];
511        }
512        NSEnumerator *dirEnum = [directoriesToScan objectEnumerator];
513        NSString *dir = nil;
514        while((dir = [dirEnum nextObject]) != nil)
515                [[self metaDataForDirectory:dir] setWatched:watched predicate:predicate];
516       
517        NSEnumerator *fileEnum = [filesToScan objectEnumerator];
518        NSString *file = nil;
519        while((file = [fileEnum nextObject]) != nil)
520                [[self metaDataForFile:file] setWatched:watched];
521}
522
523- (BOOL)favoriteForPredicate:(SapphirePredicate *)predicate
524{
525        NSArray *filesToScan = files;
526        NSArray *directoriesToScan = directories;
527        if(predicate)
528        {
529                filesToScan = [self predicatedFiles:predicate];
530                directoriesToScan = [self predicatedDirectories:predicate];
531        }
532        NSEnumerator *fileEnum = [filesToScan objectEnumerator];
533        NSString *file = nil;
534        while((file = [fileEnum nextObject]) != nil)
535                if([[self metaDataForFile:file] favorite])
536                        return YES;
537
538        NSEnumerator *dirEnum = [directoriesToScan objectEnumerator];
539        NSString *dir = nil;
540        while((dir = [dirEnum nextObject]) != nil)
541                if([[self metaDataForDirectory:dir] favoriteForPredicate:predicate])
542                        return YES;
543       
544        return NO;
545}
546
547- (void)setFavorite:(BOOL)favorite predicate:(SapphirePredicate *)predicate
548{
549        NSEnumerator *dirEnum = [directories objectEnumerator];
550        NSString *dir = nil;
551        while((dir = [dirEnum nextObject]) != nil)
552                [[self metaDataForDirectory:dir] setFavorite:favorite predicate:predicate];
553       
554        NSEnumerator *fileEnum = [files objectEnumerator];
555        NSString *file = nil;
556        while((file = [fileEnum nextObject]) != nil)
557                [[self metaDataForFile:file] setFavorite:favorite];
558}
559
560@end
561
562@implementation SapphireFileMetaData : SapphireMetaData
563
564- (void) updateMetaData
565{
566        NSDictionary *props = [[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES];
567        int modTime = [[props objectForKey:NSFileModificationDate] timeIntervalSince1970];
568       
569        if(props == nil)
570                //No file
571                return;
572       
573        if(modTime != [self modified] || [[metaData objectForKey:META_VERSION_KEY] intValue] != META_VERSION)
574        {
575                NSMutableDictionary *fileMeta = [NSMutableDictionary dictionary];
576               
577                [fileMeta setObject:[NSNumber numberWithInt:modTime] forKey:MODIFIED_KEY];
578                [fileMeta setObject:[props objectForKey:NSFileSize] forKey:SIZE_KEY];
579                [fileMeta setObject:[NSNumber numberWithInt:META_VERSION] forKey:META_VERSION_KEY];
580               
581                NSError *error = nil;
582                QTMovie *movie = [QTMovie movieWithFile:path error:&error];
583                QTTime duration = [movie duration];
584                [fileMeta setObject:[NSNumber numberWithFloat:(float)duration.timeValue/(float)duration.timeScale] forKey:DURATION_KEY];
585                NSArray *audioTracks = [movie tracksOfMediaType:@"soun"];
586                NSNumber *audioSampleRate = nil;
587                if([audioTracks count])
588                {
589                        QTTrack *track = [audioTracks objectAtIndex:0];
590                        QTMedia *media = [track media];
591                        audioSampleRate = [media attributeForKey:QTMediaTimeScaleAttribute];
592                        if(media != nil)
593                        {
594                                Media qtMedia = [media quickTimeMedia];
595                                Handle sampleDesc = NewHandle(1);
596                                GetMediaSampleDescription(qtMedia, 1, (SampleDescriptionHandle)sampleDesc);
597                                CFStringRef userText = nil;
598                                ByteCount       propSize = 0;
599                                QTSoundDescriptionGetProperty((SoundDescriptionHandle)sampleDesc, kQTPropertyClass_SoundDescription, kQTSoundDescriptionPropertyID_UserReadableText, sizeof(userText), &userText, &propSize);
600                                DisposeHandle(sampleDesc);
601                               
602                                if(userText != nil)
603                                {
604                                        [fileMeta setObject:(NSString *)userText forKey:AUDIO_DESC_KEY];
605                                        CFRelease(userText);
606                                }
607                        }
608                }
609                if(audioSampleRate != nil)
610                        [fileMeta setObject:audioSampleRate forKey:SAMPLE_RATE_KEY];
611                NSArray *videoTracks = [movie tracksOfMediaType:@"vide"];
612                if([videoTracks count])
613                {
614                        QTTrack *track = [videoTracks objectAtIndex:0];
615                        QTMedia *media = [track media];
616                        if(media != nil)
617                        {
618                                Media qtMedia = [media quickTimeMedia];
619                                Handle sampleDesc = NewHandle(1);
620                                GetMediaSampleDescription(qtMedia, 1, (SampleDescriptionHandle)sampleDesc);
621                                CFStringRef userText = nil;
622                                ByteCount       propSize = 0;
623                                ICMImageDescriptionGetProperty((ImageDescriptionHandle)sampleDesc, kQTPropertyClass_ImageDescription, kICMImageDescriptionPropertyID_SummaryString, sizeof(userText), &userText, &propSize);
624                                DisposeHandle(sampleDesc);
625                               
626                                if(userText != nil)
627                                {
628                                        [fileMeta setObject:(NSString *)userText forKey:VIDEO_DESC_KEY];
629                                        CFRelease(userText);
630                                }
631                        }
632                }
633                [metaData addEntriesFromDictionary:fileMeta];
634        }
635}
636
637- (int)modified
638{
639        return [[metaData objectForKey:MODIFIED_KEY] intValue];
640}
641
642- (BOOL)watched
643{
644        return [[metaData objectForKey:WATCHED_KEY] boolValue];
645}
646
647- (void)setWatched:(BOOL)watched
648{
649        [metaData setObject:[NSNumber numberWithBool:watched] forKey:WATCHED_KEY];
650}
651
652- (BOOL)favorite
653{
654        return [[metaData objectForKey:FAVORITE_KEY] boolValue];
655}
656
657- (void)setFavorite:(BOOL)favorite
658{
659        [metaData setObject:[NSNumber numberWithBool:favorite] forKey:FAVORITE_KEY];
660}
661
662- (unsigned int)resumeTime
663{
664        return [[metaData objectForKey:RESUME_KEY] unsignedIntValue];
665}
666
667- (void)setResumeTime:(unsigned int)resumeTime
668{
669        [metaData setObject:[NSNumber numberWithUnsignedInt:resumeTime] forKey:RESUME_KEY];
670}
671
672- (long long)size
673{
674        return [[metaData objectForKey:SIZE_KEY] longLongValue];
675}
676
677- (float)duration
678{
679        return [[metaData objectForKey:DURATION_KEY] floatValue];
680}
681
682- (int)sampleRate
683{
684        return [[metaData objectForKey:SAMPLE_RATE_KEY] intValue];
685}
686
687- (NSString *)sizeString
688{
689        float size = [self size];
690        if(size == 0)
691                return @"-";
692        char letter = ' ';
693        if(size >= 1024000)
694        {
695                if(size >= 1024*1024000)
696                {
697                        size /= 1024 * 1024 * 1024;
698                        letter = 'G';
699                }
700                else
701                {
702                        size /= 1024 * 1024;
703                        letter = 'M';
704                }
705        }
706        else if (size >= 1000)
707        {
708                size /= 1024;
709                letter = 'K';
710        }
711        return [NSString stringWithFormat:@"%.1f%cB", size, letter];   
712}
713
714- (NSString *)metaDataDescription
715{
716        NSString *name = [path lastPathComponent];
717        int duration = [self duration];
718        int secs = duration % 60;
719        int mins = (duration /60) % 60;
720        int hours = duration / 3600;
721        NSString *durationStr = nil;
722        if(hours != 0)
723                durationStr = [NSString stringWithFormat:@"%d:%02d:%02d", hours, mins, secs];
724        else if (mins != 0)
725                durationStr = [NSString stringWithFormat:@"%d:%02d", mins, secs];
726        else
727                durationStr = [NSString stringWithFormat:@"%ds", secs];
728        NSMutableString *ret = [NSMutableString stringWithFormat:
729                                                                                                   @"Name: \t%@\n"
730                                                                                                        "Duration: \t%@\n"
731                                                                                                        "Size: \t%@", name, durationStr, [self sizeString]];
732        NSString *videoDesc = [metaData objectForKey:VIDEO_DESC_KEY];
733        if(videoDesc != nil)
734                [ret appendFormat:@"\nVideo: \t%@", videoDesc];
735        NSString *audioDesc = [metaData objectForKey:AUDIO_DESC_KEY];
736        if(audioDesc != nil)
737                [ret appendFormat:@"\nAudio: \t%@", audioDesc];
738        return ret;
739}
740
741@end
Note: See TracBrowser for help on using the repository browser.