source: trunk/SapphireBrowser.m @ 311

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