source: trunk/SapphireMetaData.m @ 78

Revision 78, 21.0 KB checked in by gbooker, 7 years ago (diff)

Some more optimizations and respect the fast directory setting.

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 invalidate];
448                importTimer = nil;
449                [importArray release];
450                importArray = nil;
451        }
452}
453
454- (void)resumeDelayedImport
455{
456        [importTimer invalidate];
457        if([importArray count])
458                importTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(resumeImport) userInfo:nil repeats:NO];
459}
460
461- (SapphireMetaData *)metaDataForSubPath:(NSString *)subPath
462{
463        NSArray *components = [subPath pathComponents];
464        if(![components count])
465                return self;
466        NSString *file = [components objectAtIndex:0];
467       
468        if([self isDirectory:[path stringByAppendingPathComponent:file]])
469        {
470                NSMutableArray *newComp = [components mutableCopy];
471                [newComp removeObjectAtIndex:0];
472                [newComp autorelease];
473                SapphireDirectoryMetaData *nextLevel = [self metaDataForDirectory:file];
474                return [nextLevel metaDataForSubPath:[NSString pathWithComponents:newComp]];
475        }
476        else if([components count] > 1)
477                return nil;
478        return [self metaDataForFile:file];
479}
480
481- (NSArray *)subFileMetas
482{
483        NSMutableArray *ret = [[NSMutableArray alloc] init];
484        [self reloadDirectoryContents];
485        NSEnumerator *dirEnum = [directories objectEnumerator];
486        NSString *dir = nil;
487        while((dir = [dirEnum nextObject]) != nil)
488        {
489                SapphireDirectoryMetaData *dirMeta = [self metaDataForDirectory:dir];
490                if(dirMeta != nil)
491                        [ret addObjectsFromArray:[dirMeta subFileMetas]];
492        }
493        NSEnumerator *fileEnum = [files objectEnumerator];
494        NSString *file = nil;
495        while((file = [fileEnum nextObject]) != nil)
496        {
497                SapphireFileMetaData *fileMeta = [self metaDataForFile:file];
498                if(fileMeta != nil)
499                        [ret addObject:fileMeta];
500        }
501        return [ret autorelease];
502}
503
504- (void)scanForNewFiles
505{
506        [self reloadDirectoryContents];
507        NSEnumerator *dirEnum = [directories objectEnumerator];
508        NSString *dir = nil;
509        while((dir = [dirEnum nextObject]) != nil)
510        {
511                SapphireDirectoryMetaData *dirMeta = [self metaDataForDirectory:dir];
512                if(dirMeta != nil)
513                        [dirMeta scanForNewFiles];
514        }
515        NSEnumerator *fileEnum = [files objectEnumerator];
516        NSString *file = nil;
517        while((file = [fileEnum nextObject]) != nil)
518                [self metaDataForFile:file];
519}
520
521- (void)setupFiles:(NSArray * *)filesToScan andDirectories:(NSArray * *)directoriesToScan arraysForPredicate:(SapphirePredicate *)predicate
522{
523        if(predicate)
524        {
525                *filesToScan = [self predicatedFiles:predicate];
526                *directoriesToScan = [self predicatedDirectories:predicate];
527        }
528        else if(!scannedDirectory)
529        {
530                //Likely haven't scanned the directory yet, so use cached
531                *filesToScan = [metaFiles allKeys];
532                *directoriesToScan = [metaDirs allKeys];
533        }
534}
535
536- (BOOL)watchedForPredicate:(SapphirePredicate *)predicate
537{
538        NSArray *filesToScan = files;
539        NSArray *directoriesToScan = directories;
540        [self setupFiles:&filesToScan andDirectories:&directoriesToScan arraysForPredicate:predicate];
541        NSEnumerator *fileEnum = [filesToScan objectEnumerator];
542        NSString *file = nil;
543        while((file = [fileEnum nextObject]) != nil)
544                if(![[self metaDataForFile:file] watched])
545                        return NO;
546
547        NSEnumerator *dirEnum = [directoriesToScan objectEnumerator];
548        NSString *dir = nil;
549        while((dir = [dirEnum nextObject]) != nil)
550                if(![[self metaDataForDirectory:dir] watchedForPredicate:predicate])
551                        return NO;
552
553        return YES;
554}
555
556- (void)setWatched:(BOOL)watched predicate:(SapphirePredicate *)predicate
557{
558        [self reloadDirectoryContents];
559        NSEnumerator *dirEnum = [directories objectEnumerator];
560        NSString *dir = nil;
561        while((dir = [dirEnum nextObject]) != nil)
562                [[self metaDataForDirectory:dir] setWatched:watched predicate:predicate];
563       
564        NSEnumerator *fileEnum = [files objectEnumerator];
565        NSString *file = nil;
566        while((file = [fileEnum nextObject]) != nil)
567        {
568                SapphireFileMetaData *fileMeta = [self metaDataForFile:file];
569                if(!predicate || [predicate accept:[fileMeta path] meta:fileMeta])
570                        [fileMeta setWatched:watched];
571        }
572}
573
574- (BOOL)favoriteForPredicate:(SapphirePredicate *)predicate
575{
576        NSArray *filesToScan = files;
577        NSArray *directoriesToScan = directories;
578        [self setupFiles:&filesToScan andDirectories:&directoriesToScan arraysForPredicate:predicate];
579        NSEnumerator *fileEnum = [filesToScan objectEnumerator];
580        NSString *file = nil;
581        while((file = [fileEnum nextObject]) != nil)
582                if([[self metaDataForFile:file] favorite])
583                        return YES;
584
585        NSEnumerator *dirEnum = [directoriesToScan objectEnumerator];
586        NSString *dir = nil;
587        while((dir = [dirEnum nextObject]) != nil)
588                if([[self metaDataForDirectory:dir] favoriteForPredicate:predicate])
589                        return YES;
590       
591        return NO;
592}
593
594- (void)setFavorite:(BOOL)favorite predicate:(SapphirePredicate *)predicate
595{
596        [self reloadDirectoryContents];
597        NSEnumerator *dirEnum = [directories objectEnumerator];
598        NSString *dir = nil;
599        while((dir = [dirEnum nextObject]) != nil)
600                [[self metaDataForDirectory:dir] setFavorite:favorite predicate:predicate];
601       
602        NSEnumerator *fileEnum = [files objectEnumerator];
603        NSString *file = nil;
604        while((file = [fileEnum nextObject]) != nil)
605        {
606                SapphireFileMetaData *fileMeta = [self metaDataForFile:file];
607                if(!predicate || [predicate accept:[fileMeta path] meta:fileMeta])
608                        [fileMeta setFavorite:favorite];
609        }
610}
611
612@end
613
614@implementation SapphireFileMetaData : SapphireMetaData
615
616- (void) updateMetaData
617{
618        NSDictionary *props = [[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES];
619        int modTime = [[props objectForKey:NSFileModificationDate] timeIntervalSince1970];
620       
621        if(props == nil)
622                //No file
623                return;
624       
625        if(modTime != [self modified] || [[metaData objectForKey:META_VERSION_KEY] intValue] != META_VERSION)
626        {
627                NSMutableDictionary *fileMeta = [NSMutableDictionary dictionary];
628               
629                [fileMeta setObject:[NSNumber numberWithInt:modTime] forKey:MODIFIED_KEY];
630                [fileMeta setObject:[props objectForKey:NSFileSize] forKey:SIZE_KEY];
631                [fileMeta setObject:[NSNumber numberWithInt:META_VERSION] forKey:META_VERSION_KEY];
632               
633                NSError *error = nil;
634                QTMovie *movie = [QTMovie movieWithFile:path error:&error];
635                QTTime duration = [movie duration];
636                [fileMeta setObject:[NSNumber numberWithFloat:(float)duration.timeValue/(float)duration.timeScale] forKey:DURATION_KEY];
637                NSArray *audioTracks = [movie tracksOfMediaType:@"soun"];
638                NSNumber *audioSampleRate = nil;
639                if([audioTracks count])
640                {
641                        QTTrack *track = [audioTracks objectAtIndex:0];
642                        QTMedia *media = [track media];
643                        audioSampleRate = [media attributeForKey:QTMediaTimeScaleAttribute];
644                        if(media != nil)
645                        {
646                                Media qtMedia = [media quickTimeMedia];
647                                Handle sampleDesc = NewHandle(1);
648                                GetMediaSampleDescription(qtMedia, 1, (SampleDescriptionHandle)sampleDesc);
649                                CFStringRef userText = nil;
650                                ByteCount       propSize = 0;
651                                QTSoundDescriptionGetProperty((SoundDescriptionHandle)sampleDesc, kQTPropertyClass_SoundDescription, kQTSoundDescriptionPropertyID_UserReadableText, sizeof(userText), &userText, &propSize);
652                                DisposeHandle(sampleDesc);
653                               
654                                if(userText != nil)
655                                {
656                                        [fileMeta setObject:(NSString *)userText forKey:AUDIO_DESC_KEY];
657                                        CFRelease(userText);
658                                }
659                        }
660                }
661                if(audioSampleRate != nil)
662                        [fileMeta setObject:audioSampleRate forKey:SAMPLE_RATE_KEY];
663                NSArray *videoTracks = [movie tracksOfMediaType:@"vide"];
664                if([videoTracks count])
665                {
666                        QTTrack *track = [videoTracks objectAtIndex:0];
667                        QTMedia *media = [track media];
668                        if(media != nil)
669                        {
670                                Media qtMedia = [media quickTimeMedia];
671                                Handle sampleDesc = NewHandle(1);
672                                GetMediaSampleDescription(qtMedia, 1, (SampleDescriptionHandle)sampleDesc);
673                                CFStringRef userText = nil;
674                                ByteCount       propSize = 0;
675                                ICMImageDescriptionGetProperty((ImageDescriptionHandle)sampleDesc, kQTPropertyClass_ImageDescription, kICMImageDescriptionPropertyID_SummaryString, sizeof(userText), &userText, &propSize);
676                                DisposeHandle(sampleDesc);
677                               
678                                if(userText != nil)
679                                {
680                                        [fileMeta setObject:(NSString *)userText forKey:VIDEO_DESC_KEY];
681                                        CFRelease(userText);
682                                }
683                        }
684                }
685                [metaData addEntriesFromDictionary:fileMeta];
686        }
687}
688
689- (int)modified
690{
691        return [[metaData objectForKey:MODIFIED_KEY] intValue];
692}
693
694- (BOOL)watched
695{
696        return [[metaData objectForKey:WATCHED_KEY] boolValue];
697}
698
699- (void)setWatched:(BOOL)watched
700{
701        [metaData setObject:[NSNumber numberWithBool:watched] forKey:WATCHED_KEY];
702}
703
704- (BOOL)favorite
705{
706        return [[metaData objectForKey:FAVORITE_KEY] boolValue];
707}
708
709- (void)setFavorite:(BOOL)favorite
710{
711        [metaData setObject:[NSNumber numberWithBool:favorite] forKey:FAVORITE_KEY];
712}
713
714- (unsigned int)resumeTime
715{
716        return [[metaData objectForKey:RESUME_KEY] unsignedIntValue];
717}
718
719- (void)setResumeTime:(unsigned int)resumeTime
720{
721        [metaData setObject:[NSNumber numberWithUnsignedInt:resumeTime] forKey:RESUME_KEY];
722}
723
724- (long long)size
725{
726        return [[metaData objectForKey:SIZE_KEY] longLongValue];
727}
728
729- (float)duration
730{
731        return [[metaData objectForKey:DURATION_KEY] floatValue];
732}
733
734- (int)sampleRate
735{
736        return [[metaData objectForKey:SAMPLE_RATE_KEY] intValue];
737}
738
739- (NSString *)sizeString
740{
741        float size = [self size];
742        if(size == 0)
743                return @"-";
744        char letter = ' ';
745        if(size >= 1024000)
746        {
747                if(size >= 1024*1024000)
748                {
749                        size /= 1024 * 1024 * 1024;
750                        letter = 'G';
751                }
752                else
753                {
754                        size /= 1024 * 1024;
755                        letter = 'M';
756                }
757        }
758        else if (size >= 1000)
759        {
760                size /= 1024;
761                letter = 'K';
762        }
763        return [NSString stringWithFormat:@"%.1f%cB", size, letter];   
764}
765
766- (NSString *)metaDataDescription
767{
768        NSString *name = [path lastPathComponent];
769        int duration = [self duration];
770        int secs = duration % 60;
771        int mins = (duration /60) % 60;
772        int hours = duration / 3600;
773        NSString *durationStr = nil;
774        if(hours != 0)
775                durationStr = [NSString stringWithFormat:@"%d:%02d:%02d", hours, mins, secs];
776        else if (mins != 0)
777                durationStr = [NSString stringWithFormat:@"%d:%02d", mins, secs];
778        else
779                durationStr = [NSString stringWithFormat:@"%ds", secs];
780        NSMutableString *ret = [NSMutableString stringWithFormat:
781                                                                                                   @"Name: \t%@\n"
782                                                                                                        "Duration: \t%@\n"
783                                                                                                        "Size: \t%@", name, durationStr, [self sizeString]];
784        NSString *videoDesc = [metaData objectForKey:VIDEO_DESC_KEY];
785        if(videoDesc != nil)
786                [ret appendFormat:@"\nVideo: \t%@", videoDesc];
787        NSString *audioDesc = [metaData objectForKey:AUDIO_DESC_KEY];
788        if(audioDesc != nil)
789                [ret appendFormat:@"\nAudio: \t%@", audioDesc];
790        return ret;
791}
792
793@end
Note: See TracBrowser for help on using the repository browser.