source: trunk/SapphireMetaData.m @ 106

Revision 106, 23.8 KB checked in by gbooker, 7 years ago (diff)

These two sets of function were identical except for the selector they used on the file's meta data. Combined into less code.

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