source: trunk/SapphireMetaData.m @ 74

Revision 74, 20.8 KB checked in by gbooker, 7 years ago (diff)

Added the ability to rescan for new files in the predicated browser

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