source: trunk/SapphireBrowser.m @ 290

Revision 290, 26.5 KB checked in by pmerrill, 6 years ago (diff)
  • Normalized reported fileName (lowerCaseString)
Line 
1//
2//  SapphireBrowser.m
3//  Sapphire
4//
5//  Created by pnmerrill on 6/20/07.
6//  Copyright 2007 www.nanopi.net. All rights reserved.
7//
8
9#import "SapphireBrowser.h"
10#import <BackRow/BackRow.h>
11#import "SapphireMetaData.h"
12#import "SapphireMarkMenu.h"
13#import "SapphireMedia.h"
14#import "SapphireVideoPlayer.h"
15#import "SapphireMediaPreview.h"
16#import "SapphireTheme.h"
17#import "SapphireSettings.h"
18#import "NSString-Extensions.h"
19#import "SapphireAudioPlayer.h"
20#import "SapphireAudioMedia.h"
21#import "SapphireApplianceController.h"
22#import "SapphireFrontRowCompat.h"
23
24#import <AudioUnit/AudioUnit.h>
25#import <objc/objc-class.h>
26
27#define PASSTHROUGH_KEY         (CFStringRef)@"attemptPassthrough"
28#define A52_DOMIAN                      (CFStringRef)@"com.cod3r.a52codec"
29
30@interface SapphireBrowser (private)
31- (void)reloadDirectoryContents;
32- (void)processFiles:(NSArray *)files;
33- (void)filesProcessed:(NSDictionary *)files;
34- (NSMutableDictionary *)metaDataForPath:(NSString *)path;
35- (void)setNewPredicate:(SapphirePredicate *)newPredicate;
36@end
37
38@interface BRTVShowsSortControl (bypassAccess)
39- (BRTVShowsSortSelectorStateLayer *)gimmieDate;
40- (BRTVShowsSortSelectorStateLayer *)gimmieShow;
41- (int)gimmieState;
42@end
43
44@interface BRTVShowsSortSelectorStateLayer (bypassAccess)
45- (BRTextLayer *)gimmieDate;
46- (BRTextLayer *)gimmieShow;
47@end
48
49@interface BRMusicNowPlayingController (bypassAccess)
50- (void)setPlayer:(BRMusicPlayer *)player;
51- (BRMusicPlayer *)player;
52@end
53
54/*Private variables access, but only on BR 1.0; not used otherwise*/
55@implementation BRTVShowsSortControl (bypassAccess)
56- (BRTVShowsSortSelectorStateLayer *)gimmieDate
57{
58        return _sortedByDateWidget;
59}
60
61- (BRTVShowsSortSelectorStateLayer *)gimmieShow
62{
63        return _sortedByShowWidget;
64}
65
66- (int)gimmieState
67{
68        return _state;
69}
70
71@end
72
73@implementation BRTVShowsSortSelectorStateLayer (bypassAccess)
74- (BRTextLayer *)gimmieDate
75{
76        return _dateLayer;
77}
78
79- (BRTextLayer *)gimmieShow
80{
81        return _showLayer;
82}
83
84@end
85
86@implementation BRMusicNowPlayingController (bypassAccess)
87- (void)setPlayer:(BRMusicPlayer *)player
88{
89        Class myClass = [self class];
90        Ivar ret = class_getInstanceVariable(myClass, "_player");
91        BRMusicPlayer * *thePlayer = (BRMusicPlayer * *)(((char *)self)+ret->ivar_offset);     
92       
93        [*thePlayer release];
94        *thePlayer = [player retain];
95}
96
97- (BRMusicPlayer *)player
98{
99        Class myClass = [self class];
100        Ivar ret = class_getInstanceVariable(myClass, "_player");
101        return *(BRMusicPlayer * *)(((char *)self)+ret->ivar_offset);   
102}
103
104@end
105
106static BOOL is10Version = NO;
107
108@implementation SapphireBrowser
109
110/*!
111 * @brief Replace the text in a control with a string
112 *
113 * @param control The control on which to change the text
114 * @param str The text to put into tho control
115 */
116- (void)replaceControlText:(BRTextLayer *)control withString:(NSString *)str
117{
118        /*Create a mutable copy of the control's attributed string*/
119        NSMutableAttributedString  *dateString = [[control attributedString] mutableCopy];
120        [dateString replaceCharactersInRange:NSMakeRange(0, [dateString length]) withString:str];
121        /*Set the new string and we are done with it*/
122        [control setAttributedString:dateString];
123        [dateString release];
124}
125
126/*!
127 * @brief Creates the mode control in a compatible way
128 *
129 * @param scene The scene
130 * @param names The names in the menu
131 *
132- (void)createModeControlWithScene:(BRRenderScene *)scene names:(NSArray *)names
133{
134        /*Check for the new way to do this*
135        Class modeClass = NSClassFromString(@"BRSegmentedSortControl");
136        if(modeClass != nil)
137                /*Use the new method*
138                //Ignore this warning if compiling with backrow 1.0
139                modeControl = [[modeClass alloc] initWithScene:scene segmentNames:names selectedSegment:0];
140        else
141        {
142                /*Hack in the old way*
143                modeControl = [[BRTVShowsSortControl alloc] initWithScene:scene state:1];
144                NSString *name1 = [names objectAtIndex:0];
145                NSString *name2 = [names objectAtIndex:1];
146                [self replaceControlText:[[modeControl gimmieDate] gimmieDate] withString:name1];
147                [self replaceControlText:[[modeControl gimmieDate] gimmieShow] withString:name2];
148                [self replaceControlText:[[modeControl gimmieShow] gimmieDate] withString:name1];
149                [self replaceControlText:[[modeControl gimmieShow] gimmieShow] withString:name2];
150                is10Version = YES;
151        }
152}
153
154/*!
155 * @brief Creates a new predicated browser
156 *
157 * @param scene The scene
158 * @praam meta The metadata for the directory to browse
159 * @param newPredicate The predicate to use
160 * @return The Browser
161 */
162- (id) initWithScene: (BRRenderScene *) scene metaData: (SapphireDirectoryMetaData *)meta
163{
164        if ( [super initWithScene: scene] == nil ) return ( nil );
165               
166        _names = [NSMutableArray new];
167        items = [NSMutableArray new];
168        metaData = [meta retain];
169        [metaData setDelegate:self];
170        predicate = [[SapphireApplianceController predicate] retain];
171
172        /*Create the mode menu*/
173/*      NSArray *names = [NSArray arrayWithObjects:
174                BRLocalizedString(@"Select", @"Select Menu Item"),
175                BRLocalizedString(@"Mark File", @"Mark File Menu Item"),
176                BRLocalizedString(@"Filter", @"Filter Menu Item"),
177                nil];
178        [self createModeControlWithScene:scene names:names];
179        [self addControl:modeControl];*/
180       
181        // set the datasource *after* you've setup your array
182        [[self list] setDatasource: self] ;
183               
184        return ( self );
185}
186
187/*!
188 * @brief Override the layout
189 *
190- (void)_doLayout
191{
192        [super _doLayout];
193        NSRect listFrame = [[_listControl layer] frame];
194        /*Position the mode menu below the list*
195        NSRect modeRect;
196        modeRect.size = [modeControl preferredSizeForScreenHeight:[self masterLayerFrame].size.height];
197        modeRect.origin.y = listFrame.origin.y * 1.5f;
198        modeRect.origin.x = (listFrame.size.width - modeRect.size.width)/2 + listFrame.origin.x;
199        /*Shrink the list to make room for the mode*
200        listFrame.size.height -= listFrame.origin.y;
201        listFrame.origin.y *= 2;
202        [[_listControl layer] setFrame:listFrame];
203        [modeControl setFrame:modeRect];
204}
205
206/*!
207 * @brief Reload the display
208 */
209- (void)reloadDirectoryContents
210{
211        /*Tell the metadata to get new data*/
212        [metaData reloadDirectoryContents];
213        /*Flush our cache*/
214        [_names removeAllObjects];
215        [items removeAllObjects];
216        /*Check predicates*/
217        if(predicate == NULL)
218        {
219                /*No filtering, so just set up the dirs and files into names and the counts*/
220                NSArray *dirs = [metaData directories];
221                [_names addObjectsFromArray:dirs];
222                NSArray *files = [metaData files];
223                [_names addObjectsFromArray:files];
224                dirCount = [dirs count];
225                fileCount = [files count];
226        }
227        else
228        {
229                /*Filter the dirs and files into names and counts*/
230                NSArray *dirs = [metaData predicatedDirectories:predicate];
231                [_names addObjectsFromArray:dirs];
232                NSArray *files = [metaData predicatedFiles:predicate];
233                [_names addObjectsFromArray:files];
234                /*Put in the menu for rescan if fast switching enabled*/
235                if([[SapphireSettings sharedSettings] fastSwitching])
236                        [_names addObject:BRLocalizedString(@"< Scan for new files >", @"Conduct a scan of the directory for new files")];
237                dirCount = [dirs count];
238                fileCount = [files count];
239        }
240        /*Init the cache*/
241        int i=0, count=[_names count];
242        for(i=0; i<count; i++)
243        {
244                [items addObject:[NSNull null]];
245        }
246
247        /*Remove the dividers*/
248        BRListControl *list = [self list];
249        if([list respondsToSelector:@selector(removeDividers)])
250                [list removeDividers];
251        else
252                [list setDividerIndex:0];
253        [list removeDividerAtIndex:0];
254        /*Do a reload*/
255        [list reload];
256        /*Add dividers*/
257        int indexOffset = 0;
258        if(dirCount && fileCount)
259        {
260                [SapphireFrontRowCompat addDividerAtIndex:dirCount toList:list];
261                if(!is10Version)
262                        indexOffset++;
263        }
264        if(predicate != NULL && [[SapphireSettings sharedSettings] fastSwitching])
265                [SapphireFrontRowCompat addDividerAtIndex:dirCount + fileCount + indexOffset toList:list];
266        /*Draw*/
267        [SapphireFrontRowCompat renderScene:[self scene]];
268}
269
270- (void) dealloc
271{
272    // always remember to deallocate your resources
273        [_names release];
274        [items release];
275        [metaData release];
276        [predicate release];
277//      [modeControl release];
278    [super dealloc];
279}
280
281- (void) willBePushed
282{
283    // We're about to be placed on screen, but we're not yet there
284   
285    // always call super
286    [super willBePushed];
287        /*Reload upon display*/
288        [self setNewPredicate:[SapphireApplianceController predicate]];
289}
290
291- (void) wasPushed
292{
293    // We've just been put on screen, the user can see this controller's content now
294   
295    // always call super
296    [super wasPushed];
297        /*Get metadata when we can*/
298        [metaData resumeDelayedImport];
299}
300
301- (void) willBePopped
302{
303    // The user pressed Menu, but we've not been removed from the screen yet
304   
305    // always call super
306    [super willBePopped];
307        /*Cancel everything we were doing*/
308        [metaData cancelImport];
309        cancelScan = YES;
310        [metaData setDelegate:nil];
311}
312
313- (void) wasPopped
314{
315    // The user pressed Menu, removing us from the screen
316    // always call super
317    [super wasPopped];
318}
319
320- (void) willBeBuried
321{
322    // The user just chose an option, and we will be taken off the screen
323   
324        /*Cancel everything we were doing*/
325        [metaData cancelImport];
326        cancelScan = YES;
327        // always call super
328    [super willBeBuried];
329}
330
331- (void) wasBuriedByPushingController: (BRLayerController *) controller
332{
333    // The user chose an option and this controller is no longer on screen
334   
335    // always call super
336    [super wasBuriedByPushingController: controller];
337}
338
339- (void) willBeExhumed
340{
341    // the user pressed Menu, but we've not been revealed yet
342   
343        /*Check to see if the user stopped playing something*/
344        id controller = [[self stack] peekController];
345        float elapsed = 0.0;
346        float duration = 0.0000001; //prevent a div by 0
347        if([controller isKindOfClass:[BRVideoPlayerController class]])
348        {
349                /*Check for 90% completion*/
350                BRVideoPlayer *player = [(BRVideoPlayerController *)controller player];
351                elapsed = [player elapsedPlaybackTime];
352                duration = [player trackDuration];
353        }
354        else if([controller isKindOfClass:[BRMusicNowPlayingController class]])
355        {
356                BRMusicPlayer *player = [(BRMusicNowPlayingController *)controller player];
357                elapsed = [player elapsedPlaybackTime];
358                duration = [player trackDuration];
359                [player stop];
360        }
361        if(elapsed / duration > 0.9f)
362                /*Mark as watched and reload info*/
363                [currentPlayFile setWatched:YES];
364       
365        /*Get the resume time to save*/
366        if(elapsed < duration - 2)
367                [currentPlayFile setResumeTime:elapsed];
368        else
369                [currentPlayFile setResumeTime:0];
370        [currentPlayFile writeMetaData];
371
372        /*cleanup*/
373        [currentPlayFile release];
374        currentPlayFile = nil;
375        /*Reload our display*/
376        [self setNewPredicate:[SapphireApplianceController predicate]];
377    // always call super
378    [super willBeExhumed];
379}
380
381- (void) wasExhumedByPoppingController: (BRLayerController *) controller
382{
383    // handle being revealed when the user presses Menu
384   
385    // always call super
386    [super wasExhumedByPoppingController: controller];
387        /*Check to see if dir is empty*/
388        if(fileCount + dirCount == 0)
389                [[self stack] popController];
390        else
391                /*Resume importing now that we are up again*/
392                [metaData resumeDelayedImport];
393        //Turn off the AC3 Passthrough hack
394        CFPreferencesSetAppValue(PASSTHROUGH_KEY, (CFNumberRef)[NSNumber numberWithInt:0], A52_DOMIAN);
395        CFPreferencesAppSynchronize(A52_DOMIAN);
396}
397
398- (long) itemCount
399{
400    // return the number of items in your menu list here
401        if([_names count])
402                return ( [ _names count]);
403        // Put up an empty item
404        return 1;
405}
406
407- (id<BRMenuItemLayer>) itemForRow: (long) row
408{
409/*
410    // build a BRTextMenuItemLayer or a BRAdornedMenuItemLayer, etc. here
411    // return that object, it will be used to display the list item.
412    return ( nil );
413*/
414        NSString * displayName=nil ;
415        FileClass fileCls=0 ;
416        /*Check for no items*/
417        int nameCount = [_names count];
418        if( nameCount == 0)
419        {
420                BRAdornedMenuItemLayer *result = [SapphireFrontRowCompat textMenuItemForScene:[self scene] folder:NO];
421                [SapphireFrontRowCompat setTitle:BRLocalizedString(@"< EMPTY >", @"Empty directory") forMenu:result];
422                return result;
423        }
424        if( row >= nameCount ) return ( nil ) ;
425       
426        /*Check our cache*/
427        id cached = [items objectAtIndex:row];
428        if(cached != [NSNull null])
429                return cached;
430        NSString *name = [_names objectAtIndex:row];
431        // Pad filename to correcrtly display gem icons
432        BRAdornedMenuItemLayer * result = nil;
433        BOOL watched = NO;
434        BOOL favorite = NO;
435        BOOL gear = NO;
436        BRRenderScene *scene = [self scene];
437        /*Is this a dir*/
438        if(row < dirCount)
439        {
440                result = [SapphireFrontRowCompat textMenuItemForScene:scene folder:YES];
441                SapphireDirectoryMetaData *meta = [metaData metaDataForDirectory:name];
442                watched = [meta watchedForPredicate:predicate];
443                favorite = [meta favoriteForPredicate:predicate];
444        }
445        /*Check for a file next*/
446        else if(row < dirCount + fileCount)
447        {
448                result = [SapphireFrontRowCompat textMenuItemForScene:scene folder:NO];
449                SapphireFileMetaData *meta = [metaData metaDataForFile:name];
450                if(meta != nil)
451                {
452                        fileCls=[meta fileClass] ;
453                        if(fileCls==FILE_CLASS_TV_SHOW)
454                        {
455                                /*Display episode number if availble*/
456                                int eps= [meta episodeNumber] ;
457                                displayName=[meta episodeTitle] ;
458                                if(eps>0)
459                                        [SapphireFrontRowCompat setRightJustifiedText:[NSString stringWithFormat:@" %02d",eps] forMenu:result];
460                                else
461                                        /*Fallback to size*/
462                                        [SapphireFrontRowCompat setRightJustifiedText:[meta sizeString] forMenu:result];
463                        }
464                        if(fileCls==FILE_CLASS_MOVIE)
465                        {
466                                displayName=[meta movieTitle] ;
467                        }
468                        watched = [meta watched];
469                        favorite = [meta favorite] ;
470                }
471        }
472        /*Utility*/
473        else
474        {
475                result = [SapphireFrontRowCompat textMenuItemForScene:scene folder:NO];
476                gear = YES;
477        }
478        /*Add icons*/
479        SapphireTheme *theme = [SapphireTheme sharedTheme];
480        if(gear) [SapphireFrontRowCompat setLeftIcon:[theme gem:GEAR_GEM_KEY] forMenu:result];
481        else if(!watched) [SapphireFrontRowCompat setLeftIcon:[theme gem:BLUE_GEM_KEY] forMenu:result];
482        else if(favorite) [SapphireFrontRowCompat setLeftIcon:[theme gem:YELLOW_GEM_KEY] forMenu:result];
483        else if(fileCls==FILE_CLASS_AUDIO)[SapphireFrontRowCompat setLeftIcon:[theme gem:GREEN_GEM_KEY] forMenu:result];
484        else [SapphireFrontRowCompat setLeftIcon:[theme gem:RED_GEM_KEY] forMenu:result];
485                       
486        // add text
487        if(displayName)name= displayName ;
488        name=[@"   " stringByAppendingString: name] ;
489        [SapphireFrontRowCompat setTitle:name forMenu:result];
490        [items replaceObjectAtIndex:row withObject:result];
491                               
492        return ( result ) ;
493}
494
495- (NSString *) titleForRow: (long) row
496{
497
498        if ( row >= [ _names count] ) return ( nil );
499       
500        NSString *result = [ _names objectAtIndex: row] ;
501       
502        return ([@"  ????? " stringByAppendingString: result] ) ;
503}
504
505- (long) rowForTitle: (NSString *) title
506{
507    long result = -1;
508    long i, count = [self itemCount];
509    for ( i = 0; i < count; i++ )
510    {
511        if ( [title isEqualToString: [self titleForRow: i]] )
512        {
513            result = i;
514            break;
515        }
516    }
517   
518    return ( result );
519}
520
521BOOL findCorrectDescriptionForStream(AudioStreamID streamID, int sampleRate)
522{
523        OSStatus err;
524        UInt32 propertySize = 0;
525        err = AudioStreamGetPropertyInfo(streamID, 0, kAudioStreamPropertyPhysicalFormats, &propertySize, NULL);
526       
527        if(err != noErr || propertySize == 0)
528                return NO;
529       
530        AudioStreamBasicDescription *descs = malloc(propertySize);
531        if(descs == NULL)
532                return NO;
533       
534        int formatCount = propertySize / sizeof(AudioStreamBasicDescription);
535        err = AudioStreamGetProperty(streamID, 0, kAudioStreamPropertyPhysicalFormats, &propertySize, descs);
536       
537        if(err != noErr)
538        {
539                free(descs);
540                return NO;
541        }
542       
543        int i;
544        BOOL ret = NO;
545        for(i=0; i<formatCount; i++)
546        {
547                if (descs[i].mBitsPerChannel == 16 && descs[i].mFormatID == kAudioFormatLinearPCM)
548                {
549                        if(descs[i].mSampleRate == sampleRate)
550                        {
551                                err = AudioStreamSetProperty(streamID, NULL, 0, kAudioStreamPropertyPhysicalFormat, sizeof(AudioStreamBasicDescription), descs + i);
552                                if(err != noErr)
553                                        continue;
554                                ret = YES;
555                                break;
556                        }
557                }
558        }
559        free(descs);
560        return ret;
561}
562
563BOOL setupDevice(AudioDeviceID devID, int sampleRate)
564{
565        OSStatus err;
566        UInt32 propertySize = 0;
567        err = AudioDeviceGetPropertyInfo(devID, 0, FALSE, kAudioDevicePropertyStreams, &propertySize, NULL);
568       
569        if(err != noErr || propertySize == 0)
570                return NO;
571       
572        AudioStreamID *streams = malloc(propertySize);
573        if(streams == NULL)
574                return NO;
575       
576        int streamCount = propertySize / sizeof(AudioStreamID);
577        err = AudioDeviceGetProperty(devID, 0, FALSE, kAudioDevicePropertyStreams, &propertySize, streams);
578        if(err != noErr)
579        {
580                free(streams);
581                return NO;
582        }
583       
584        int i;
585        BOOL ret = NO;
586        for(i=0; i<streamCount; i++)
587        {
588                if(findCorrectDescriptionForStream(streams[i], sampleRate))
589                {
590                        ret = YES;
591                        break;
592                }
593        }
594        free(streams);
595        return ret;
596}
597
598BOOL setupAudioOutput(int sampleRate)
599{
600        OSErr err;
601        UInt32 propertySize = 0;
602       
603        err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propertySize, NULL);
604        if(err != noErr || propertySize == 0)
605                return NO;
606       
607        AudioDeviceID *devs = malloc(propertySize);
608        if(devs == NULL)
609                return NO;
610       
611        err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propertySize, devs);
612        if(err != noErr)
613        {
614                free(devs);
615                return NO;
616        }
617       
618        int i, devCount = propertySize/sizeof(AudioDeviceID);
619        BOOL ret = NO;
620        for(i=0; i<devCount; i++)
621        {
622                if(setupDevice(devs[i], sampleRate))
623                {
624                        err = AudioHardwareSetProperty(kAudioHardwarePropertyDefaultOutputDevice, sizeof(AudioDeviceID), devs + i);
625                        if(err != noErr)
626                                continue;
627                        ret = YES;
628                        break;
629                }
630        }
631        free(devs);
632        return ret;
633}
634
635- (void)setNewPredicate:(SapphirePredicate *)newPredicate
636{
637        [newPredicate retain];
638        [predicate release];
639        predicate = newPredicate;
640        [self setListIcon:[SapphireApplianceController gemForPredicate:predicate]];
641        [self reloadDirectoryContents];
642}
643
644- (void) itemSelected: (long) row
645{
646    // This is called when the user presses play/pause on a list item
647       
648        if([_names count] == 0)
649        {
650                /*No items, so leave the empty dir*/
651                [[self stack] popController];
652                return;
653        }
654       
655        NSString *name = [_names objectAtIndex:row];
656       
657        /*Check for dir*/
658        if(row < dirCount)
659        {
660                /*Browse the subdir*/
661                id controller = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:[metaData metaDataForDirectory:name]];
662                [controller setListTitle:name];
663                [controller setListIcon:[self listIcon]];
664                [[self stack] pushController:controller];
665                [controller release];
666        }
667        else if(row < dirCount + fileCount)
668        {
669                /*Play the file*/
670                currentPlayFile = [[metaData metaDataForFile:name] retain];
671               
672                NSString *path = [currentPlayFile path];
673               
674                /*Anonymous reporting*/
675                SapphireSettings *settings = [SapphireSettings sharedSettings];
676                if(![settings disableAnonymousReporting])
677                {
678                        NSMutableString *reqData = [NSMutableString string];
679                        NSMutableArray *reqComp = [NSMutableArray array];
680                        NSMutableURLRequest *request=nil;
681                       
682                       
683                        if([currentPlayFile fileClass]==FILE_CLASS_TV_SHOW)
684                        {
685                                request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://appletv.nanopi.net/show.php"]];
686                                int ep = [currentPlayFile episodeNumber];
687                                int season = [currentPlayFile seasonNumber];
688                                NSString *showID = [currentPlayFile showID];
689                                NSString *showName= [currentPlayFile showName];
690                               
691                                if(season != 0)
692                                        [reqComp addObject:[NSString stringWithFormat:@"season=%d", season]];
693                                if(ep != 0)
694                                        [reqComp addObject:[NSString stringWithFormat:@"ep=%d", ep]];
695                                if(showName != 0)
696                                        [reqComp addObject:[NSString stringWithFormat:@"showname=%@", showName]];
697                                if(showID != 0)
698                                        [reqComp addObject:[NSString stringWithFormat:@"showid=%@", showID]];
699                                if(path != 0)
700                                        [reqComp addObject:[NSString stringWithFormat:@"path=%@", [[path lastPathComponent]lowercaseString]]];
701                        }
702                        else if([currentPlayFile fileClass]==FILE_CLASS_MOVIE)
703                        {
704                                request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://appletv.nanopi.net/movie.php"]];
705                                NSString *movieTitle=[currentPlayFile movieTitle];
706                                NSDate * releaseDate=[currentPlayFile movieReleaseDate];
707                       
708                                if(movieTitle != 0)
709                                        [reqComp addObject:[NSString stringWithFormat:@"title=%@", movieTitle]];
710                                if(releaseDate != 0)
711                                        [reqComp addObject:[NSString stringWithFormat:@"year=%@", [releaseDate descriptionWithCalendarFormat:@"%Y" timeZone:nil locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]]];
712                                if(path != 0)
713                                        [reqComp addObject:[NSString stringWithFormat:@"path=%@", [[path lastPathComponent]lowercaseString]]];
714                        }
715                       
716                        int count = [reqComp count];
717                        int i;
718                        for(i=0; i<count-1; i++)
719                        {
720                                [reqData appendFormat:@"%@&", [reqComp objectAtIndex:i]];
721                        }
722                        if(count)
723                                [reqData appendFormat:@"%@", [reqComp objectAtIndex:i]];
724                       
725                        NSData *postData = [reqData dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
726                       
727                        [request setHTTPMethod:@"POST"];
728                        [request setValue:[NSString stringWithFormat:@"%d", [postData length]] forHTTPHeaderField:@"Content-Length"];
729                        [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
730                        [request setHTTPBody:postData];
731                        [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
732                        /*Trigger the req*/
733                        NSURLDownload *download = [[NSURLDownload alloc] initWithRequest:request delegate:nil];
734                        [download autorelease];
735                }
736               
737                /*AC3 passthrough*/
738                BOOL useAC3Passthrough = NO;
739                if([currentPlayFile updateMetaData])
740                        [currentPlayFile writeMetaData];
741                if([settings useAC3Passthrough])
742                {
743                        Float64 sampleRate = [currentPlayFile sampleRate];
744                        UInt32 type = [currentPlayFile audioFormatID];
745                       
746                        if((type == 'ac-3' || type == 0x6D732000) && setupAudioOutput((int)sampleRate))
747                                useAC3Passthrough = YES;
748                }
749               
750                if(useAC3Passthrough)
751                        CFPreferencesSetAppValue(PASSTHROUGH_KEY, (CFNumberRef)[NSNumber numberWithInt:1], A52_DOMIAN);                 
752                else
753                        CFPreferencesSetAppValue(PASSTHROUGH_KEY, (CFNumberRef)[NSNumber numberWithInt:0], A52_DOMIAN);
754                CFPreferencesAppSynchronize(A52_DOMIAN);
755               
756                if([[SapphireMetaData videoExtensions] containsObject:[path pathExtension]] && [currentPlayFile hasVideo])
757                {
758                        /*Video*/
759                        /*Set the asset resume time*/
760                        NSURL *url = [NSURL fileURLWithPath:path];
761                        SapphireMedia *asset  =[[SapphireMedia alloc] initWithMediaURL:url];
762                        [asset setResumeTime:[currentPlayFile resumeTime]];
763                       
764                        /*Get the player*/
765                        SapphireVideoPlayer *player = [[SapphireVideoPlayer alloc] init];
766                        NSError *error = nil;
767                        [player setMedia:asset error:&error];
768                       
769                        /*and go*/
770                        BRVideoPlayerController *controller = [BRVideoPlayerController alloc];
771                        if([controller respondsToSelector:@selector(initWithScene:)])
772                                controller = [controller initWithScene:[self scene]];
773                        else
774                                controller = [controller init];
775                        [controller setAllowsResume:YES];
776                        [controller setVideoPlayer:player];
777                        [[self stack] pushController:controller];
778
779                        [asset release];
780                        [player release];
781                        [controller release];
782                }
783                else
784                {
785                        /*Audio*/
786                        /*Set the asset*/
787                        NSURL *url = [NSURL fileURLWithPath:path];
788                        SapphireAudioMedia *asset  =[[SapphireAudioMedia alloc] initWithMediaURL:url];
789                        [asset setResumeTime:[currentPlayFile resumeTime]];
790                       
791                        SapphireAudioPlayer *player = [[SapphireAudioPlayer alloc] init];
792                        NSError *error = nil;
793                        [player setMedia:asset inTracklist:[NSArray arrayWithObject:asset] error:&error];
794                       
795                        /*and go*/
796                        BRMusicNowPlayingController *controller = [BRMusicNowPlayingController alloc];
797                        if([controller respondsToSelector:@selector(initWithScene:)])
798                                controller = [controller initWithScene:[self scene]];
799                        else
800                                controller = [controller init];
801                        [controller setPlayer:player];
802                        [player setElapsedPlaybackTime:[currentPlayFile resumeTime]];
803                        [player play];
804                        [[self stack] pushController:controller];
805                       
806                        [asset release];
807                        [player release];
808                        [controller release];
809                }
810        }
811        else
812        {
813                /*Do a scan*/
814                cancelScan = NO;
815                [metaData scanForNewFilesWithDelegate:self skipDirectories:[NSMutableSet set]];
816        }
817}
818
819/*!
820 * @brief Finished scanning the dir
821 *
822 * @param subs nil in this case
823 */
824- (void)gotSubFiles:(NSArray *)subs
825{
826        [self reloadDirectoryContents];
827}
828
829/*!
830* @brief Meta data delegate method to inform on its scanning progress
831 *
832 * @param dir The current directory it is scanning
833 */
834- (void)scanningDir:(NSString *)dir
835{
836}
837
838/*!
839 * @brief Check to see if the scan should be canceled
840 *
841 * @return YES if the scan should be canceled
842 */
843- (BOOL)getSubFilesCanceled
844{
845        return cancelScan;
846}
847
848- (id<BRMediaPreviewController>) previewControlForItem: (long) row
849{
850        return [self previewControllerForItem:row];
851}
852
853- (id<BRMediaPreviewController>) previewControllerForItem: (long) row
854{
855    // If subclassing BRMediaMenuController, this function is called when the selection cursor
856    // passes over an item.
857        if(row >= [_names count])
858                return nil;
859        /*Check to see if it is a dir or file*/
860        NSString *name = [_names objectAtIndex:row];
861        if(row < dirCount + fileCount)
862        {
863                SapphireMediaPreview *preview = [[SapphireMediaPreview alloc] initWithScene:[self scene]];
864                /*Check for dir*/
865                if(row < dirCount)
866                        [preview setMetaData:[metaData metaDataForDirectory:name]];
867                else
868                        [preview setMetaData:[metaData metaDataForFile:name]];
869                [preview setShowsMetadataImmediately:NO];
870                /*And go*/
871                return [preview autorelease];
872        }
873    return ( nil );
874}
875
876- (int)getSelection
877{
878        BRListControl *list = [self list];
879        int row;
880        NSMethodSignature *signature = [list methodSignatureForSelector:@selector(selection)];
881        NSInvocation *selInv = [NSInvocation invocationWithMethodSignature:signature];
882        [selInv setSelector:@selector(selection)];
883        [selInv invokeWithTarget:list];
884        if([signature methodReturnLength] == 8)
885        {
886                double retDoub = 0;
887                [selInv getReturnValue:&retDoub];
888                row = retDoub;
889        }
890        else
891                [selInv getReturnValue:&row];
892        return row;
893}
894
895- (BOOL)brEventAction:(BREvent *)event
896{
897        /*Cancel imports on an action*/
898        [metaData resumeDelayedImport];
899       
900        BREventPageUsageHash hashVal = [event pageUsageHash];
901        if ([(BRControllerStack *)[self stack] peekController] != self)
902                hashVal = 0;
903       
904        switch (hashVal)
905        {
906                case kBREventTapRight:
907                {
908                        id meta = nil;
909                        int row = [self getSelection];
910                        if(row > [_names count])
911                                return NO;
912                       
913                        NSString *name = [_names objectAtIndex:row];
914                       
915                        /*Get metadata*/
916                        if(row < dirCount)
917                                meta = [metaData metaDataForDirectory:name];
918                        else if (row < dirCount + fileCount)
919                                meta = [metaData metaDataForFile:name];
920                        else
921                                return NO;
922                        /*Do mark menu*/
923                        id controller = [[SapphireMarkMenu alloc] initWithScene:[self scene] metaData:meta];
924                        [(SapphireMarkMenu *)controller setPredicate:predicate];
925                        [[self stack] pushController:controller];
926                        [controller release];
927                        return YES;
928                }
929                case kBREventTapLeft:
930                        [self setNewPredicate:[SapphireApplianceController nextPredicate]];
931                        return YES;
932                default:
933                        return [super brEventAction:event];
934        }
935        return NO;
936}
937
938/*!
939 * @brief The import on a file completed
940 *
941 * @param file Filename to the file which completed
942 */
943- (void)updateCompleteForFile:(NSString *)file
944{
945        /*Get the file*/
946        int index = [_names indexOfObject:file];
947        if(index != NSNotFound)
948                [items replaceObjectAtIndex:index withObject:[NSNull null]];
949        /*Relead the list and render*/
950        BRListControl *list = [self list];
951        [list reload];
952        [SapphireFrontRowCompat renderScene:[self scene]];
953}
954
955@end
Note: See TracBrowser for help on using the repository browser.