source: trunk/SapphireApplianceController.m @ 2

Revision 2, 10.4 KB checked in by gbooker, 8 years ago (diff)

Tracking metadata information.

Line 
1//
2//  SapphireApplianceController.m
3//  Sapphire
4//
5//  Created by pnmerrill on 6/20/07.
6//  Copyright 2007 __MyCompanyName__. All rights reserved.
7//
8
9#import "SapphireApplianceController.h"
10#import <BackRow/BackRow.h>
11
12#define FILES_KEY @"Files"
13#define DIRS_KEY @"Dirs"
14
15#define MODIFIED_KEY @"Modified"
16
17@implementation NSString (episodeSorting)
18
19// Custom TV Episode handler
20- (NSComparisonResult) episodeCompare:(NSString *)other
21{
22        return [self compare:other options:NSCaseInsensitiveSearch | NSNumericSearch];
23}
24
25@end
26
27@interface SapphireApplianceController (private)
28- (BOOL)pruneMetaDataWithFiles:(NSArray *)files andDirectories:(NSArray *)dirs;
29- (BOOL)updateMetaDataWithFiles:(NSArray *)files andDirectories:(NSArray *)dirs;
30@end
31
32@implementation SapphireApplianceController
33
34// Static set of file extensions to filter
35static NSArray *extensions = nil;
36static NSString *metaPath = nil;
37static NSMutableDictionary *mainMetaDictionary = nil;
38
39+(void)load
40{
41        extensions = [[NSArray alloc] initWithObjects:@"avi", @"mov", @"mpg", @"wmv", nil];
42        metaPath = [[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/metaData.plist"] retain];
43        mainMetaDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:metaPath];
44        if(mainMetaDictionary == nil)
45        {
46                mainMetaDictionary = [[NSMutableDictionary alloc] init];
47        }
48}
49
50+ (NSString *) rootMenuLabel
51{
52        return (@"net.pmerrill.recursivemenu.root" );
53}
54
55static void makeParentDir(NSFileManager *manager, NSString *dir)
56{
57        NSString *parent = [dir stringByDeletingLastPathComponent];
58       
59        BOOL isDir;
60        if(![manager fileExistsAtPath:parent isDirectory:&isDir])
61                makeParentDir(manager, parent);
62        else if(!isDir)
63                //Can't work with this
64                return;
65       
66        [manager createDirectoryAtPath:dir attributes:nil];
67}
68
69+ (void)writeMetaData
70{
71        makeParentDir([NSFileManager defaultManager], [metaPath stringByDeletingLastPathComponent]);
72        [mainMetaDictionary writeToFile:metaPath atomically:YES];
73}
74
75//
76- (id) initWithScene: (BRRenderScene *) scene
77{
78/*
79    if ( [super initWithScene: scene] == nil )
80        return ( nil );
81   
82    // initialize your resources here
83   
84    return ( self );
85*/
86        return ( [self initWithScene: scene directory:[NSHomeDirectory() stringByAppendingPathComponent:@"Movies"] metaData:mainMetaDictionary] );
87}
88
89- (id) initWithScene: (BRRenderScene *) scene directory: (NSString *) dir metaData: (NSMutableDictionary *)meta;
90{
91        BOOL modifiedMeta = NO;
92        if ( [super initWithScene: scene] == nil ) return ( nil );
93        _dir = [dir retain];
94               
95        _names = [NSMutableArray new];
96        _metaData = [meta retain];
97        _metaFiles = [meta objectForKey:FILES_KEY];
98        if(_metaFiles == nil)
99        {
100                _metaFiles = [NSMutableDictionary dictionary];
101                [meta setObject:_metaFiles forKey:FILES_KEY];
102                modifiedMeta = YES;
103        }
104        _metaDirs = [meta objectForKey:DIRS_KEY];
105        if(_metaDirs == nil)
106        {
107                _metaDirs = [NSMutableDictionary dictionary];
108                [meta setObject:_metaDirs forKey:DIRS_KEY];
109                modifiedMeta = YES;
110        }
111       
112        NSMutableArray *files = [NSMutableArray array];
113       
114        NSArray *names = [[[NSFileManager defaultManager] directoryContentsAtPath:dir] retain];
115       
116        NSEnumerator *nameEnum = [names objectEnumerator];
117        NSString *name = nil;
118        // Display Menu Items
119        while((name = [nameEnum nextObject]) != nil)
120        {
121                if([name hasPrefix:@"."])
122                        continue;
123                //Only accept if it is a directory or right extension
124                NSString *extension = [name pathExtension];
125                if([extensions containsObject:extension])
126                        [files addObject:name];
127                else if([self isDirectory:[_dir stringByAppendingPathComponent:name]])
128                        [_names addObject:name];
129        }
130        modifiedMeta |= [self pruneMetaDataWithFiles:files andDirectories:_names];
131        modifiedMeta |= [self updateMetaDataWithFiles:files andDirectories:_names];
132        [_names sortUsingSelector:@selector(episodeCompare:)];
133        [files sortUsingSelector:@selector(episodeCompare:)];
134        [_names addObjectsFromArray:files];
135       
136        if(modifiedMeta)
137                [SapphireApplianceController writeMetaData];
138       
139        // set the datasource *after* you've setup your array
140        [[self list] setDatasource: self] ;
141               
142        return ( self );
143}
144
145- (void) dealloc
146{
147    // always remember to deallocate your resources
148        [_dir release];
149        [_names release];
150        [_metaData release];
151    [super dealloc];
152}
153
154//Check to see if the path is a directory
155- (BOOL)isDirectory:(NSString *)path
156{
157        BOOL isDir = NO;
158        return [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir] && isDir;
159}
160
161- (BOOL)pruneMetaDataWithFiles:(NSArray *)files andDirectories:(NSArray *)dirs
162{
163        BOOL ret = NO;
164        NSSet *existingSet = [NSSet setWithArray:files];
165        NSArray *metaArray = [_metaFiles allKeys];
166        NSMutableSet *pruneSet = [NSMutableSet setWithArray:metaArray];
167
168        [pruneSet minusSet:existingSet];
169        if([pruneSet anyObject] != nil)
170        {
171                NSEnumerator *pruneEnum = [pruneSet objectEnumerator];
172                NSString *pruneKey = nil;
173                while((pruneKey = [pruneEnum nextObject]) != nil)
174                        [_metaFiles removeObjectForKey:pruneKey];
175                ret = YES;             
176        }
177       
178        existingSet = [NSSet setWithArray:dirs];
179        metaArray = [_metaDirs allKeys];
180        pruneSet = [NSMutableSet setWithArray:metaArray];
181       
182        [pruneSet minusSet:existingSet];
183        if([pruneSet anyObject] != nil)
184        {
185                NSEnumerator *pruneEnum = [pruneSet objectEnumerator];
186                NSString *pruneKey = nil;
187                while((pruneKey = [pruneEnum nextObject]) != nil)
188                        [_metaDirs removeObjectForKey:pruneKey];
189                ret = YES;
190        }
191       
192        return ret;
193}
194
195- (BOOL)updateMetaDataWithFiles:(NSArray *)files andDirectories:(NSArray *)dirs
196{
197        BOOL ret = NO;
198        NSArray *metaArray = [_metaDirs allKeys];
199        NSSet *metaSet = [NSSet setWithArray:metaArray];
200        NSMutableSet *newSet = [NSMutableSet setWithArray:dirs];
201       
202        [newSet minusSet:metaSet];
203        if([newSet anyObject] != nil)
204        {
205                NSEnumerator *newEnum = [newSet objectEnumerator];
206                NSString *newKey = nil;
207                while((newKey = [newEnum nextObject]) != nil)
208                        [_metaDirs setObject:[NSMutableDictionary dictionary] forKey:newKey];
209                ret = YES;
210        }
211
212        NSEnumerator *fileEnum = [files objectEnumerator];
213        NSString *fileName = nil;
214        NSMutableArray *newFiles = [NSMutableArray array];
215        while((fileName = [fileEnum nextObject]) != nil)
216        {
217                NSDictionary *fileMeta = [_metaFiles objectForKey:fileName];
218                if(fileMeta == nil)
219                        [newFiles addObject:fileName];
220                else
221                {
222                        NSString *path = [_dir stringByAppendingPathComponent:fileName];
223                        NSDictionary *props = [[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES];
224                        NSDate *modDate = [props objectForKey:NSFileModificationDate];
225                        if([[fileMeta objectForKey:MODIFIED_KEY] intValue] != [modDate timeIntervalSince1970])
226                                [newFiles addObject:fileName];
227                }
228        }
229        //Do something in a thread to process newFiles
230       
231        return ret;
232}
233
234- (void) willBePushed
235{
236    // We're about to be placed on screen, but we're not yet there
237   
238    // always call super
239    [super willBePushed];
240}
241
242- (void) wasPushed
243{
244    // We've just been put on screen, the user can see this controller's content now
245   
246    // always call super
247    [super wasPushed];
248}
249
250- (void) willBePopped
251{
252    // The user pressed Menu, but we've not been removed from the screen yet
253   
254    // always call super
255    [super willBePopped];
256}
257
258- (void) wasPopped
259{
260    // The user pressed Menu, removing us from the screen
261   
262    // always call super
263    [super wasPopped];
264}
265
266- (void) willBeBuried
267{
268    // The user just chose an option, and we will be taken off the screen
269   
270    // always call super
271    [super willBeBuried];
272}
273
274- (void) wasBuriedByPushingController: (BRLayerController *) controller
275{
276    // The user chose an option and this controller os no longer on screen
277   
278    // always call super
279    [super wasBuriedByPushingController: controller];
280}
281
282- (void) willBeExhumed
283{
284    // the user pressed Menu, but we've not been revealed yet
285   
286    // always call super
287    [super willBeExhumed];
288}
289
290- (void) wasExhumedByPoppingController: (BRLayerController *) controller
291{
292    // handle being revealed when the user presses Menu
293   
294    // always call super
295    [super wasExhumedByPoppingController: controller];
296}
297
298- (long) itemCount
299{
300    // return the number of items in your menu list here
301        return ( [ _names count]);
302}
303
304- (id<BRMenuItemLayer>) itemForRow: (long) row
305{
306/*
307    // build a BRTextMenuItemLayer or a BRAdornedMenuItemLayer, etc. here
308    // return that object, it will be used to display the list item.
309    return ( nil );
310*/
311        if( row > [_names count] ) return ( nil ) ;
312       
313        BRAdornedMenuItemLayer * result = nil ;
314        NSString *name = [_names objectAtIndex:row];
315        if([self isDirectory:[_dir stringByAppendingPathComponent:name]])
316                result = [BRAdornedMenuItemLayer adornedFolderMenuItemWithScene: [self scene]] ;
317        else
318                        result = [BRAdornedMenuItemLayer adornedMenuItemWithScene: [self scene]] ;
319                       
320        // add text
321        [[result textItem] setTitle: name] ;
322                               
323        return ( result ) ;
324}
325
326- (NSString *) titleForRow: (long) row
327{
328
329        if ( row > [ _names count] ) return ( nil );
330       
331        NSString *result = [ _names objectAtIndex: row] ;
332        return ( result ) ;
333/*
334    // return the title for the list item at the given index here
335    return ( @"Sapphire" );
336*/
337}
338
339- (long) rowForTitle: (NSString *) title
340{
341    long result = -1;
342    long i, count = [self itemCount];
343    for ( i = 0; i < count; i++ )
344    {
345        if ( [title isEqualToString: [self titleForRow: i]] )
346        {
347            result = i;
348            break;
349        }
350    }
351   
352    return ( result );
353}
354
355- (void) itemSelected: (long) row
356{
357    // This is called when the user presses play/pause on a list item
358       
359        NSString *name = [_names objectAtIndex:row];
360       
361        if([self isDirectory:[_dir stringByAppendingPathComponent:name]])
362        {
363                id controller = [[SapphireApplianceController alloc] initWithScene:[self scene] directory:[_dir stringByAppendingPathComponent:name] metaData:[_metaDirs objectForKey:name]];
364                [[self stack] pushController:controller];
365                [controller release];
366        }
367        else
368        {
369                BRVideoPlayerController *controller = [[BRVideoPlayerController alloc] initWithScene:[self scene]];
370                BRQTKitVideoPlayer *player = [[BRQTKitVideoPlayer alloc] init];
371                NSError *error = nil;
372               
373                NSURL *url = [NSURL fileURLWithPath:[_dir stringByAppendingPathComponent:name]];
374                BRSimpleMediaAsset *asset  =[[BRSimpleMediaAsset alloc] initWithMediaURL:url];
375                [player setMedia:asset error:&error];
376               
377                [controller setVideoPlayer:player];
378                [[self stack] pushController:controller];
379
380                [asset release];
381                [player release];
382                [controller release];
383        }
384}
385
386- (id<BRMediaPreviewController>) previewControllerForItem: (long) item
387{
388    // If subclassing BRMediaMenuController, this function is called when the selection cursor
389    // passes over an item.
390    return ( nil );
391}
392
393@end
Note: See TracBrowser for help on using the repository browser.