Merge branch 'master' of git://github.com/ksuther/MenuTunes
[MenuTunes.git] / iTunesRemote.m
index ef53fc5..dbd21fb 100755 (executable)
        
        //Loop through each source
        for (i = 1; i <= numSources; i++) {
-        SInt32 fourcc = [ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pKnd'), from:obj { form:'indx', want:type('cSrc'), seld:long(%i), from:() } }", i], 'core', 'getd', &savedPSN) int32Value]; //Type of the current source
+        FourCharCode fourcc = [ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pKnd'), from:obj { form:'indx', want:type('cSrc'), seld:long(%i), from:() } }", i], 'core', 'getd', &savedPSN) typeCodeValue]; //Type of the current source
         NSString *sourceName = [ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cSrc'), seld:long(%i), from:() } }", i], 'core', 'getd', &savedPSN) stringValue]; //Name of the current source
         SInt32 index = [ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pidx'), from:obj { form:'indx', want:type('cSrc'), seld:long(%i), from:() } }", i], 'core', 'getd', &savedPSN) int32Value]; //Index of the current source
         ITMTRemotePlayerSource class; //The class of the current source
                                                newParent = test;
                                        }
                                }
+                               [[[nextNode parent] children] removeObject:nextNode];
                                [nextNode setParent:newParent];
                                [[newParent children] addObject:nextNode];
                                [newParent setType:ITMTFolderNode];
                NSEnumerator *nestEnumerator = [nested objectEnumerator];
                while ( (nextNode = [nestEnumerator nextObject]) ) {
                        [[sourceNode children] removeObject:nextNode];
+                       [nested removeObject:nextNode];
                }
                [nested release];
                
                enumerator = [[sourceNode children] reverseObjectEnumerator];
                while ( (nextNode = [enumerator nextObject]) ) {
                        if ([nextNode type] == ITMTPodcastsNode) {
-                               [nextNode retain];
                                [[sourceNode children] removeObject:nextNode];
                                [[sourceNode children] insertObject:nextNode atIndex:1];
                                movedPodcasts = YES;
                        } else if ([nextNode type] == ITMTFolderNode) {
-                               [nextNode retain];
                                [[sourceNode children] removeObject:nextNode];
                                [[sourceNode children] insertObject:nextNode atIndex:1 + movedPodcasts];
                        }
 
 - (NSArray *)artists
 {
-    NSAppleEventDescriptor *rawr = ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pArt'), from:obj { form:'indx', want:type('cTrk'), seld:abso($616C6C20$), from:obj { form:'indx', want:type('cPly'), seld:long(1), from:obj { form:'indx', want:type('cSrc'), seld:long(1), from:() } } } }", 'core', 'getd', &savedPSN);
+    NSAppleEventDescriptor *rawr = ITSendAEWithStringAndTimeout(@"'----':obj { form:'prop', want:type('prop'), seld:type('pArt'), from:obj { form:'indx', want:type('cTrk'), seld:abso($616C6C20$), from:obj { form:'indx', want:type('cPly'), seld:long(1), from:obj { form:'indx', want:type('cSrc'), seld:long(1), from:() } } } }", 'core', 'getd', &savedPSN, 600);
     int i;
     NSMutableArray *array = [[NSMutableArray alloc] init];
     NSArray *returnArray;
 
 - (NSArray *)albums
 {
-    NSAppleEventDescriptor *rawr = ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pAlb'), from:obj { form:'indx', want:type('cTrk'), seld:abso($616C6C20$), from:obj { form:'indx', want:type('cPly'), seld:long(1), from:obj { form:'indx', want:type('cSrc'), seld:long(1), from:() } } } }", 'core', 'getd', &savedPSN);
+    NSAppleEventDescriptor *rawr = ITSendAEWithStringAndTimeout(@"'----':obj { form:'prop', want:type('prop'), seld:type('pAlb'), from:obj { form:'indx', want:type('cTrk'), seld:abso($616C6C20$), from:obj { form:'indx', want:type('cPly'), seld:long(1), from:obj { form:'indx', want:type('cSrc'), seld:long(1), from:() } } } }", 'core', 'getd', &savedPSN, 600);
     int i;
     NSMutableArray *array = [[NSMutableArray alloc] init];
     NSArray *returnArray;
 
     ITDebugLog(@"Getting current source.");   
     
-    fourcc = ([self isPlaying]) ? [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pKnd'), from:obj { form:'prop', want:type('prop'), seld:type('ctnr'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }", 'core', 'getd', &savedPSN) int32Value] : 'kLib';
+    fourcc = ([self isPlaying]) ? [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pKnd'), from:obj { form:'prop', want:type('prop'), seld:type('ctnr'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }", 'core', 'getd', &savedPSN) typeCodeValue] : 'kLib';
     
     switch (fourcc) {
         case 'kTun':
 
 - (ITMTRemotePlayerPlaylistClass)currentPlaylistClass
 {
-    SInt32 realResult;
+    FourCharCode realResult;
     ITDebugLog(@"Getting current playlist class");
-    realResult = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pcls'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
+    realResult = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pcls'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }", 'core', 'getd', &savedPSN) typeCodeValue];
     switch (realResult)
           {
           case 'cLiP':
     return ( ([temp1 length]) ? temp1 : nil ) ;
 }
 
+- (BOOL)songEnabledAtIndex:(int)index
+{
+    BOOL temp1;
+    ITDebugLog(@"Getting song enabled at index %i.", index);
+    temp1 = [ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('enbl'), from:obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }", index], 'core', 'getd', &savedPSN) booleanValue];
+    ITDebugLog(@"Getting song enabled at index %i done.", index);
+    return temp1;
+}
+
 - (int)currentAlbumTrackCount
 {
     int temp1;
     NSString *temp1;
     ITDebugLog(@"Getting current unique identifier.");
        NSAppleEventDescriptor *descriptor = ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pcls'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN);
-       if ([descriptor int32Value] == 'prop') {
+       if ([descriptor typeCodeValue] == 'prop') {
                return @"0-0";
        } else if (descriptor == nil) {
                return nil;
        }
-    SInt32 cls = [descriptor int32Value];
+    FourCharCode cls = [descriptor typeCodeValue];
     if ( ([self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist) || (cls == 'cURT') ) {
                NSString *bad = [NSString stringWithUTF8String:"浳湧"];
         temp1 = [ITSendAEWithKey('pStT', 'core', 'getd', &savedPSN) stringValue];
 {
     NSString *temp1;
     ITDebugLog(@"Getting current song title.");
-    SInt32 result = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pcls'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
+    FourCharCode result = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pcls'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) typeCodeValue];
        
     //If we're listening to the radio.
     if (result == 'cURT') {
     return temp2;
 }
 
+- (int)currentSongPlayed
+{
+       UInt32 final;
+    ITDebugLog(@"Getting current song played time.");
+       final = [ITSendAEWithKey('pPos', 'core', 'getd', &savedPSN) int32Value];
+    ITDebugLog(@"Getting current song played time done.");
+    return final;
+}
+
+- (int)currentSongDuration
+{
+    SInt32 temp1;
+    ITDebugLog(@"Getting current song duration.");
+    temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pDur'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
+    ITDebugLog(@"Getting current song duration done.");
+    return temp1;
+}
+
 - (NSString *)currentSongRemaining
 {
     SInt32 duration, current, final;
 {
     ITDebugLog(@"Getting current song album art.");
     NSData *data = ([self isPlaying]) ? [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pPCT'), from:obj { form:'indx', want:type('cArt'), seld:long(1), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } } }", 'core', 'getd', &savedPSN) data] : nil;
-    ITDebugLog(@"Getting current song album art done.");    
+    ITDebugLog(@"Getting current song album art done.");
     if (data) {
         return [[[NSImage alloc] initWithData:data] autorelease];
     } else {
     return YES;
 }
 
+- (BOOL)currentSongShufflable
+{
+       BOOL temp1;
+       ITDebugLog(@"Getting current song shufflable status.");
+    temp1 = (![self isPlaying] || ([self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist)) ? NO : [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pSfa'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) booleanValue];
+    ITDebugLog(@"Getting current song shufflable status done.");
+    return temp1;
+}
+
+- (BOOL)setCurrentSongShufflable:(BOOL)shufflable
+{
+       ITDebugLog(@"Setting current song shufflable status to %i.", shufflable);
+    if ([self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist) {
+               ITDebugLog(@"Not a valid track to set status to, returning.");
+               return NO;
+       }
+       ITSendAEWithString([NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pSfa'), from:obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }", shufflable, [self currentSongIndex]], 'core', 'setd', &savedPSN);
+    ITDebugLog(@"Setting current song shufflable status to %i done.", shufflable);
+    return YES;
+}
+
 - (BOOL)equalizerEnabled
 {
     ITDebugLog(@"Getting equalizer enabled status.");
 
 - (BOOL)isPlaying
 {
-       return ([ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pcls'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value] != 'prop');
+       return ([ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pcls'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) typeCodeValue] != 'prop');
 }
 
 - (void)notificationHandler:(NSNotification *)note
                 ITDebugLog(@"iTunes' highLPongOfPSN: %lu.", number.highLongOfPSN);
                 ITDebugLog(@"iTunes' lowLongOfPSN: %lu.", number.lowLongOfPSN);
                 ITDebugLog(@"Done getting iTunes' PSN.");
+                               [(NSString *)name release];
                 return number;
             }
             [(NSString *)name release];