source: trunk/SapphireMetaData.m @ 82

Revision 82, 21.1 KB checked in by gbooker, 7 years ago (diff)

crasher fix

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