1 #import "iTunesRemote.h"
3 @implementation iTunesRemote
7 return [[[iTunesRemote alloc] init] autorelease];
10 - (NSString *)remoteTitle
12 return @"iTunes Remote";
15 - (NSString *)remoteInformation
17 return @"Default MenuTunes plugin to control iTunes, by iThink Software.";
20 - (NSImage *)remoteIcon
27 ITDebugLog(@"iTunesRemote begun");
28 savedPSN = [self iTunesPSN];
34 ITDebugLog(@"iTunesRemote halted");
38 - (NSString *)playerFullName
43 - (NSString *)playerSimpleName
48 - (NSDictionary *)capabilities
50 return [NSDictionary dictionaryWithObjectsAndKeys:
51 [NSNumber numberWithBool: YES], @"Remote",
52 [NSNumber numberWithBool: YES], @"Basic Track Control",
53 [NSNumber numberWithBool: YES], @"Track Information",
54 [NSNumber numberWithBool: YES], @"Track Navigation",
55 [NSNumber numberWithBool: YES], @"Upcoming Songs",
56 [NSNumber numberWithBool: YES], @"Playlists",
57 [NSNumber numberWithBool: YES], @"Volume",
58 [NSNumber numberWithBool: YES], @"Shuffle",
59 [NSNumber numberWithBool: YES], @"Repeat Modes",
60 [NSNumber numberWithBool: YES], @"Equalizer",
61 [NSNumber numberWithBool: YES], @"Track Rating",
65 - (BOOL)showPrimaryInterface
67 ITDebugLog(@"Showing player primary interface.");
69 if ([self playerRunningState] == ITMTRemotePlayerRunning) {
70 ITDebugLog(@"Showing player interface.");
71 //If not minimized and visible
72 if ( ([ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pMin'), from:obj { form:'indx', want:type('cBrW'), seld:1, from:'null'() } }", 'core', 'getd', &savedPSN) booleanValue] == 0) &&
73 ([ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pvis'), from:obj { form:'indx', want:type('cBrW'), seld:1, from:'null'() } }", 'core', 'getd', &savedPSN) booleanValue] != 0) &&
74 [[[[NSWorkspace sharedWorkspace] activeApplication] objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"] ) {
75 //set minimized of browser window 1 to true
76 ITSendAEWithString(@"data:long(1), '----':obj { form:'prop', want:type('prop'), seld:type('pMin'), from:obj { form:'indx', want:type('cBrW'), seld:1, from:'null'() } }", 'core', 'setd', &savedPSN);
78 //set minimized of browser window 1 to false
79 ITSendAEWithString(@"data:long(0), '----':obj { form:'prop', want:type('prop'), seld:type('pMin'), from:obj { form:'indx', want:type('cBrW'), seld:1, from:'null'() } }", 'core', 'setd', &savedPSN);
81 //set visible of browser window 1 to true
82 ITSendAEWithString(@"data:long(1), '----':obj { form:'prop', want:type('prop'), seld:type('pvis'), from:obj { form:'indx', want:type('cBrW'), seld:1, from:'null'() } }", 'core', 'setd', &savedPSN);
84 ITSendAEWithString(@"data:long(1), '----':obj { form:'prop', want:type('prop'), seld:type('pisf'), from:'null'() }", 'core', 'setd', &savedPSN);
85 ITDebugLog(@"Done showing player primary interface.");
89 ITDebugLog(@"Launching player.");
90 if ( (path = [[NSUserDefaults standardUserDefaults] stringForKey:@"CustomPlayerPath"]) ) {
92 path = [self playerFullName];
94 if (![[NSWorkspace sharedWorkspace] launchApplication:path]) {
95 ITDebugLog(@"Error Launching Player");
102 - (ITMTRemotePlayerRunningState)playerRunningState
104 NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
106 int count = [apps count];
108 for (i = 0; i < count; i++) {
109 if ([[[apps objectAtIndex:i] objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) {
110 ITDebugLog(@"Player running state: 1");
111 return ITMTRemotePlayerRunning;
114 ITDebugLog(@"Player running state: 0");
115 return ITMTRemotePlayerNotRunning;
118 - (ITMTRemotePlayerPlayingState)playerPlayingState
122 ITDebugLog(@"Getting player playing state");
123 result = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pPlS'), from:'null'() }", 'core', 'getd', &savedPSN) int32Value];
127 ITDebugLog(@"Getting player playing state done. Player state: Playing");
128 return ITMTRemotePlayerPlaying;
130 ITDebugLog(@"Getting player playing state done. Player state: Paused");
131 return ITMTRemotePlayerPaused;
133 ITDebugLog(@"Getting player playing state done. Player state: Rewinding");
134 return ITMTRemotePlayerRewinding;
136 ITDebugLog(@"Getting player playing state done. Player state: Forwarding");
137 return ITMTRemotePlayerForwarding;
140 ITDebugLog(@"Getting player playing state done. Player state: Stopped");
141 return ITMTRemotePlayerStopped;
143 ITDebugLog(@"Getting player playing state done. Player state: Stopped");
144 return ITMTRemotePlayerStopped;
147 /*- (NSArray *)playlists
150 const signed long numPlaylists = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cPly'), '----':()" eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
151 NSMutableArray *playlists = [[NSMutableArray alloc] initWithCapacity:numPlaylists];
153 for (i = 1; i <= numPlaylists; i++) {
155 NSString *sendStr = [NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cPly'), seld:long(%lu), from:'null'() } }",(unsigned long)j];
156 NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:sendStr eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
157 [playlists addObject:theObj];
159 return [playlists autorelease];
162 //Full source awareness
163 - (NSArray *)playlists
166 SInt32 numSources = [ITSendAEWithString(@"kocl:type('cSrc'), '----':()", 'core', 'cnte', &savedPSN) int32Value];
167 NSMutableArray *allSources = [[NSMutableArray alloc] init];
169 ITDebugLog(@"Getting playlists.");
170 if (numSources == 0) {
171 ITDebugLog(@"No sources.");
175 for (k = 1; k <= numSources ; k++) {
176 SInt32 numPlaylists = [ITSendAEWithString([NSString stringWithFormat:@"kocl:type('cPly'), '----':obj { form:'indx', want:type('cSrc'), seld:long(%u), from:() }",k], 'core', 'cnte', &savedPSN) int32Value];
177 SInt32 fourcc = [ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pKnd'), from:obj { form:'indx', want:type('cSrc'), seld:long(%u), from:() } }",k], 'core', 'getd', &savedPSN) int32Value];
178 NSString *sourceName = [ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cSrc'), seld:long(%u), from:() } }",k], 'core', 'getd', &savedPSN) stringValue];
179 SInt32 index = [ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pidx'), from:obj { form:'indx', want:type('cSrc'), seld:long(%u), from:() } }",k], 'core', 'getd', &savedPSN) int32Value];
182 NSMutableArray *aSource = [[NSMutableArray alloc] init];
183 [aSource addObject:sourceName];
186 class = ITMTRemoteRadioSource;
189 class = ITMTRemoteGenericDeviceSource;
192 class = ITMTRemoteiPodSource;
196 class = ITMTRemoteCDSource;
199 class = ITMTRemoteSharedLibrarySource;
204 class = ITMTRemoteLibrarySource;
207 ITDebugLog(@"Adding source %@ of type %i at index %i", sourceName, class, index);
208 [aSource addObject:[NSNumber numberWithInt:class]];
209 [aSource addObject:[NSNumber numberWithInt:index]];
210 for (i = 1; i <= numPlaylists; i++) {
211 NSString *sendStr = [NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cPly'), seld:long(%u), from:obj { form:'indx', want:type('cSrc'), seld:long(%u), from:() } } }",i,k];
212 NSString *theObj = [ITSendAEWithString(sendStr, 'core', 'getd', &savedPSN) stringValue];
213 ITDebugLog(@" - Adding playlist %@", theObj);
215 [aSource addObject:theObj];
218 [allSources addObject:[aSource autorelease]];
220 ITDebugLog(@"Source at index %i disappeared.", k);
223 ITDebugLog(@"Finished getting playlists.");
224 return [allSources autorelease];
229 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);
231 NSMutableArray *array = [[NSMutableArray alloc] init];
232 NSArray *returnArray;
233 for (i = 1; i <= [rawr numberOfItems]; i++) {
234 NSString *artist = [[rawr descriptorAtIndex:i] stringValue];
235 if (artist && [artist length] && ![array containsObject:artist]) {
236 [array addObject:artist];
239 [array sortUsingSelector:@selector(caseInsensitiveCompare:)];
240 returnArray = [NSArray arrayWithArray:array];
247 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);
249 NSMutableArray *array = [[NSMutableArray alloc] init];
250 NSArray *returnArray;
251 for (i = 1; i <= [rawr numberOfItems]; i++) {
252 NSString *album = [[rawr descriptorAtIndex:i] stringValue];
253 if (album && [album length] && ![array containsObject:album]) {
254 [array addObject:album];
257 [array sortUsingSelector:@selector(caseInsensitiveCompare:)];
258 returnArray = [NSArray arrayWithArray:array];
263 - (int)numberOfSongsInPlaylistAtIndex:(int)index
266 This method only returns the proper number if there's something playing.
267 This is because it gets the container of the current playlist so that it
268 gets the playlist index from the current source. Operating this way is fine,
269 since MT only ever calls this method when there is something playlist.
270 A working version of this that works in just the main source is in the
271 makePlaylistWithTerm:ofType: method.
274 ITDebugLog(@"Getting number of songs in playlist at index %i", index);
275 temp1 = (int)[ITSendAEWithString([NSString stringWithFormat:@"kocl:type('cTrk'), '----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('ctnr'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }", index], 'core', 'cnte', &savedPSN) int32Value];
276 ITDebugLog(@"Getting number of songs in playlist at index %i done", index);
280 - (ITMTRemotePlayerSource)currentSource
284 ITDebugLog(@"Getting current source.");
286 fourcc = [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];
290 ITDebugLog(@"Getting current source done. Source: Radio.");
291 return ITMTRemoteRadioSource;
294 ITDebugLog(@"Getting current source done. Source: Generic Device.");
295 return ITMTRemoteGenericDeviceSource;
297 ITDebugLog(@"Getting current source done. Source: iPod.");
298 return ITMTRemoteiPodSource; //this is stupid
302 ITDebugLog(@"Getting current source done. Source: CD.");
303 return ITMTRemoteCDSource;
306 ITDebugLog(@"Getting current source done. Source: Shared Library.");
307 return ITMTRemoteSharedLibrarySource;
312 ITDebugLog(@"Getting current source done. Source: Library.");
313 return ITMTRemoteLibrarySource;
318 - (int)currentSourceIndex
320 ITDebugLog(@"Getting current source.");
321 return [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pidx'), 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];
324 - (ITMTRemotePlayerPlaylistClass)currentPlaylistClass
327 ITDebugLog(@"Getting current playlist class");
328 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];
332 ITDebugLog(@"Getting current playlist class done. Class: Library.");
333 return ITMTRemotePlayerLibraryPlaylist;
336 ITDebugLog(@"Getting current playlist class done. Class: Radio.");
337 return ITMTRemotePlayerRadioPlaylist;
340 ITDebugLog(@"Getting current playlist class done. Class: Standard playlist.");
341 return ITMTRemotePlayerPlaylist;
345 - (int)currentPlaylistIndex
348 ITDebugLog(@"Getting current playlist index.");
349 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pidx'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
350 ITDebugLog(@"Getting current playlist index done.");
354 - (NSString *)songTitleAtIndex:(int)index
357 ITDebugLog(@"Getting song title at index %i.", index);
358 temp1 = [ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), 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) stringValue];
359 ITDebugLog(@"Getting song title at index %i done.", index);
360 return ( ([temp1 length]) ? temp1 : nil ) ;
363 - (int)currentAlbumTrackCount
366 ITDebugLog(@"Getting current album track count.");
367 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pTrC'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
368 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { temp1 = 0; }
369 ITDebugLog(@"Getting current album track count done.");
373 - (int)currentSongTrack
376 ITDebugLog(@"Getting current song track.");
377 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pTrN'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
378 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { temp1 = 0; }
379 ITDebugLog(@"Getting current song track done.");
383 - (NSString *)playerStateUniqueIdentifier
386 ITDebugLog(@"Getting current unique identifier.");
387 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);
388 if (descriptor == nil) {
391 SInt32 cls = [descriptor int32Value];
392 if ( ([self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist) || (cls == 'cURT') ) {
393 NSString *bad = [NSString stringWithUTF8String:"浳湧"];
394 temp1 = [ITSendAEWithKey('pStT', 'core', 'getd', &savedPSN) stringValue];
395 if ([temp1 isEqualToString:bad]) {
396 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) stringValue];
399 temp1 = [NSString stringWithFormat:@"%i-%i", [self currentPlaylistIndex], [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pDID'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value]];
401 ITDebugLog(@"Getting current unique identifier done.");
402 return ( ([temp1 length]) ? temp1 : nil ) ;
405 - (int)currentSongIndex
408 ITDebugLog(@"Getting current song index.");
409 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pidx'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
410 ITDebugLog(@"Getting current song index done.");
414 - (NSString *)currentSongTitle
417 ITDebugLog(@"Getting current song title.");
419 //If we're listening to the radio.
420 if ([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] == 'cURT') {
421 NSString *bad = [NSString stringWithUTF8String:"浳湧"];
422 temp1 = [ITSendAEWithKey('pStT', 'core', 'getd', &savedPSN) stringValue];
423 if ([temp1 isEqualToString:bad]) {
424 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) stringValue];
426 temp1 = [temp1 stringByAppendingString:@" (Stream)"];
428 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) stringValue];
430 ITDebugLog(@"Getting current song title done.");
431 return ( ([temp1 length]) ? temp1 : nil ) ;
434 - (NSString *)currentSongArtist
437 ITDebugLog(@"Getting current song artist.");
438 if ( [self currentPlaylistClass] != ITMTRemotePlayerRadioPlaylist ) {
439 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pArt'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) stringValue];
443 ITDebugLog(@"Getting current song artist done.");
444 return ( ([temp1 length]) ? temp1 : nil ) ;
447 - (NSString *)currentSongComposer
450 ITDebugLog(@"Getting current song artist.");
451 if ( [self currentPlaylistClass] != ITMTRemotePlayerRadioPlaylist ) {
452 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pCmp'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) stringValue];
456 ITDebugLog(@"Getting current song artist done.");
457 return ( ([temp1 length]) ? temp1 : nil ) ;
460 - (NSString *)currentSongAlbum
463 ITDebugLog(@"Getting current song album.");
464 if ( [self currentPlaylistClass] != ITMTRemotePlayerRadioPlaylist ) {
465 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pAlb'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) stringValue];
469 ITDebugLog(@"Getting current song album done.");
470 return ( ([temp1 length]) ? temp1 : nil ) ;
473 - (NSString *)currentSongGenre
476 ITDebugLog(@"Getting current song genre.");
477 temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pGen'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) stringValue];
478 ITDebugLog(@"Getting current song genre done.");
479 return ( ([temp1 length]) ? temp1 : nil ) ;
482 - (NSString *)currentSongLength
486 ITDebugLog(@"Getting current song length.");
487 temp1 = [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];
488 temp2 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pTim'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) stringValue];
489 if ( ([self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist) || (temp1 == 'cURT') ) { temp2 = @"Continuous"; }
490 ITDebugLog(@"Getting current song length done.");
494 - (NSString *)currentSongRemaining
496 SInt32 duration, current, final;
497 NSString *finalString;
499 ITDebugLog(@"Getting current song remaining time.");
501 duration = [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];
502 current = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pPos'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
503 final = duration - current;
504 finalString = [self formatTimeInSeconds:final];
506 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { finalString = nil; }
508 ITDebugLog(@"Getting current song remaining time done.");
513 - (NSString *)currentSongElapsed
516 NSString *finalString;
518 ITDebugLog(@"Getting current song elapsed time.");
519 final = (long)[ITSendAEWithKey('pPos', 'core', 'getd', &savedPSN) int32Value];
520 finalString = [self formatTimeInSeconds:final];
521 ITDebugLog(@"Getting current song elapsed time done.");
525 - (NSImage *)currentSongAlbumArt
527 ITDebugLog(@"Getting current song album art.");
528 NSData *data = [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];
529 ITDebugLog(@"Getting current song album art done.");
531 return [[[NSImage alloc] initWithData:data] autorelease];
537 - (int)currentSongPlayCount
540 ITDebugLog(@"Getting current song play count.");
541 count = (int)[ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pPlC'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
542 ITDebugLog(@"Getting current song play count done.");
546 - (float)currentSongRating
549 ITDebugLog(@"Getting current song rating.");
550 temp1 = ((float)[ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pRte'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value] / 100.0);
551 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { temp1 = -1.0; }
552 ITDebugLog(@"Getting current song rating done.");
556 - (BOOL)setCurrentSongRating:(float)rating
558 ITDebugLog(@"Setting current song rating to %f.", rating);
559 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { return NO; }
560 ITSendAEWithString([NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pRte'), from:obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } } }",(long)(rating*100), [self currentSongIndex]], 'core', 'setd', &savedPSN);
561 ITDebugLog(@"Setting current song rating to %f done.", rating);
565 - (BOOL)equalizerEnabled
567 ITDebugLog(@"Getting equalizer enabled status.");
568 int thingy = (int)[ITSendAEWithKey('pEQ ', 'core', 'getd', &savedPSN) int32Value];
569 ITDebugLog(@"Done getting equalizer enabled status.");
570 return (thingy != 0) ? YES : NO;
573 - (BOOL)setEqualizerEnabled:(BOOL)enabled
575 ITDebugLog(@"Setting equalizer enabled to %i.", enabled);
576 ITSendAEWithString([NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pEQ '), from:'null'() }", enabled], 'core', 'setd', &savedPSN);
577 ITDebugLog(@"Done setting equalizer enabled to %i.", enabled);
581 - (NSArray *)eqPresets
584 SInt32 numPresets = [ITSendAEWithString(@"kocl:type('cEQP'), '----':(), &subj:()", 'core', 'cnte', &savedPSN) int32Value];
585 NSMutableArray *presets = [[NSMutableArray alloc] initWithCapacity:numPresets];
586 ITDebugLog(@"Getting EQ presets");
587 for (i = 1; i <= numPresets; i++) {
588 NSString *theObj = [ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cEQP'), seld:long(%lu), from:'null'() } }", i], 'core', 'getd', &savedPSN) stringValue];
590 ITDebugLog(@"Adding preset %@", theObj);
591 [presets addObject:theObj];
594 ITDebugLog(@"Done getting EQ presets");
595 return [presets autorelease];
598 - (int)currentEQPresetIndex
601 ITDebugLog(@"Getting current EQ preset index.");
602 result = (int)[ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pidx'), from:obj { form:'prop', want:type('prop'), seld:type('pEQP'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
603 ITDebugLog(@"Getting current EQ preset index done.");
609 ITDebugLog(@"Getting volume.");
610 ITDebugLog(@"Getting volume done.");
611 return (float)[ITSendAEWithKey('pVol', 'core', 'getd', &savedPSN) int32Value] / 100;
614 - (BOOL)setVolume:(float)volume
616 ITDebugLog(@"Setting volume to %f.", volume);
617 ITSendAEWithString([NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pVol'), from:'null'() }", (long)(volume * 100)], 'core', 'setd', &savedPSN);
618 ITDebugLog(@"Setting volume to %f done.", volume);
622 - (BOOL)shuffleEnabled
624 ITDebugLog(@"Getting shuffle enabled status.");
626 int result = (int)[ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pShf'), from:obj { form:'prop', want:type('pPla'), seld:type('pEQP'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
632 ITDebugLog(@"Getting shuffle enabled status done.");
636 - (BOOL)setShuffleEnabled:(BOOL)enabled
638 ITDebugLog(@"Set shuffle enabled to %i", enabled);
639 ITSendAEWithString([NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pShf'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }", (unsigned long)enabled], 'core', 'setd', &savedPSN);
640 ITDebugLog(@"Set shuffle enabled to %i done", enabled);
644 - (ITMTRemotePlayerRepeatMode)repeatMode
646 FourCharCode m00f = 0;
648 m00f = (FourCharCode)[ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pRpt'), from:obj { form:'prop', want:type('pPla'), seld:type('pEQP'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value];
649 ITDebugLog(@"Getting repeat mode.");
654 ITDebugLog(@"Repeat off");
655 result = ITMTRemotePlayerRepeatOff;
658 ITDebugLog(@"Repeat one");
659 result = ITMTRemotePlayerRepeatOne;
662 ITDebugLog(@"Repeat all");
663 result = ITMTRemotePlayerRepeatAll;
666 ITDebugLog(@"Getting repeat mode done.");
670 - (BOOL)setRepeatMode:(ITMTRemotePlayerRepeatMode)repeatMode
673 ITDebugLog(@"Setting repeat mode to %i", repeatMode);
676 case ITMTRemotePlayerRepeatOne:
679 case ITMTRemotePlayerRepeatAll:
682 case ITMTRemotePlayerRepeatOff:
687 ITSendAEWithString([NSString stringWithFormat:@"data:'%s', '----':obj { form:'prop', want:type('prop'), seld:type('pRpt'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:() } }", m00f], 'core', 'setd', &savedPSN);
688 ITDebugLog(@"Setting repeat mode to %c done", m00f);
695 ITSendAE('hook', 'Play', &savedPSN);
696 ITDebugLog(@"Play done");
702 ITDebugLog(@"Pause");
703 ITSendAE('hook', 'Paus', &savedPSN);
704 ITDebugLog(@"Pause done");
710 ITDebugLog(@"Go to next track");
711 ITSendAE('hook', 'Next', &savedPSN);
712 ITDebugLog(@"Go to next track done");
716 - (BOOL)goToPreviousSong
718 ITDebugLog(@"Go to previous track");
719 ITSendAE('hook', 'Prev', &savedPSN);
720 ITDebugLog(@"Go to previous track done");
726 ITDebugLog(@"Fast forward action");
727 ITSendAE('hook', 'Fast', &savedPSN);
728 ITDebugLog(@"Fast forward action done");
734 ITDebugLog(@"Rewind action");
735 ITSendAE('hook', 'Rwnd', &savedPSN);
736 ITDebugLog(@"Rewind action done");
740 - (BOOL)switchToPlaylistAtIndex:(int)index
742 ITDebugLog(@"Switching to playlist at index %i", index);
743 ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:() }", index], 'hook', 'Play', &savedPSN);
744 ITDebugLog(@"Done switching to playlist at index %i", index);
748 - (BOOL)switchToPlaylistAtIndex:(int)index ofSourceAtIndex:(int)index2
750 ITDebugLog(@"Switching to playlist at index %i of source %i", index, index2);
751 ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from: obj { form:'indx', want:type('cSrc'), seld:long(%lu), from:'null'() } }", index - 1, index2 + 1], 'hook', 'Play', &savedPSN);
752 ITDebugLog(@"Done switching to playlist at index %i of source %i", index, index2);
756 - (BOOL)switchToSongAtIndex:(int)index
758 ITDebugLog(@"Switching to track at index %i", index);
759 ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:() } }", index], 'hook' ,'Play', &savedPSN);
760 ITDebugLog(@"Done switching to track at index %i", index);
764 - (BOOL)switchToEQAtIndex:(int)index
766 ITDebugLog(@"Switching to EQ preset at index %i", index);
767 // index should count from 0, but itunes counts from 1, so let's add 1.
768 [self setEqualizerEnabled:YES];
769 ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pEQP'), from:'null'() }, data:obj { form:'indx', want:type('cEQP'), seld:long(%lu), from:'null'() }", (index+1)], 'core', 'setd', &savedPSN);
770 ITDebugLog(@"Done switching to EQ preset at index %i", index);
774 - (BOOL)makePlaylistWithTerm:(NSString *)term ofType:(int)type
778 //Get fixed indexing status
779 BOOL fixed = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pFix'), from:'null'() }", 'core', 'getd', &savedPSN) booleanValue];
781 //Enabled fixed indexing
782 ITSendAEWithString(@"data:long(1), '----':obj { form:'prop', want:type('prop'), seld:type('pFix'), from:'null'() }", 'core', 'setd', &savedPSN);
784 //Search for the term
785 NSAppleEventDescriptor *searchResults = ITSendAEWithString([NSString stringWithFormat:@"pTrm:\"%@\", pAre:'%@', '----':obj { form:'indx', want:type('cPly'), seld:long(1), from:obj { form:'indx', want:type('cSrc'), seld:long(1), from:'null'() } }", term, ((type == 1) ? @"kSrR" : @"kSrL")], 'hook', 'Srch', &savedPSN);
787 //If MenuTunes playlist exists
788 if ([ITSendAEWithString(@"'----':obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", 'core', 'doex', &savedPSN) booleanValue]) {
789 //Clear old MenuTunes playlist
790 int numSongs = [ITSendAEWithString(@"kocl:type('cTrk'), '----':obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", 'core', 'cnte', &savedPSN) int32Value];
791 for (i = 1; i <= numSongs; i++) {
792 ITSendAEWithString(@"'----':obj { form:'indx', want:type('cTrk'), seld:long(1), from:obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() } }", 'core', 'delo', &savedPSN);
795 //Create MenuTunes playlist
796 ITSendAEWithString(@"prdt:{ pnam:\"MenuTunes\" }, kocl:type('cPly'), &subj:()", 'core', 'crel', &savedPSN);
799 //Duplicate search results to playlist
800 for (i = 1; i <= [searchResults numberOfItems]; i++) {
801 ITSendAEWithStringAndObject(@"insh:obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", [[searchResults descriptorAtIndex:i] aeDesc], 'core', 'clon', &savedPSN);
803 //Reset fixed indexing
804 ITSendAEWithString([NSString stringWithFormat:@"data:long(%i), '----':obj { form:'prop', want:type('prop'), seld:type('pFix'), from:'null'() }", fixed], 'core', 'setd', &savedPSN);
806 //Play MenuTunes playlist
807 ITSendAEWithString(@"'----':obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", 'hook', 'Play', &savedPSN);
812 - (ProcessSerialNumber)iTunesPSN
814 /*NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
815 ProcessSerialNumber number;
817 int count = [apps count];
819 number.highLongOfPSN = kNoProcess;
821 for (i = 0; i < count; i++)
823 NSDictionary *curApp = [apps objectAtIndex:i];
825 if ([[curApp objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"])
827 number.highLongOfPSN = [[curApp objectForKey:
828 @"NSApplicationProcessSerialNumberHigh"] intValue];
829 number.lowLongOfPSN = [[curApp objectForKey:
830 @"NSApplicationProcessSerialNumberLow"] intValue];
834 ProcessSerialNumber number;
835 number.highLongOfPSN = kNoProcess;
836 number.lowLongOfPSN = 0;
837 ITDebugLog(@"Getting iTunes' PSN.");
838 while ( (GetNextProcess(&number) == noErr) )
841 if ( (CopyProcessName(&number, &name) == noErr) )
843 if ([(NSString *)name isEqualToString:@"iTunes"])
845 ITDebugLog(@"iTunes' highLPongOfPSN: %lu.", number.highLongOfPSN);
846 ITDebugLog(@"iTunes' lowLongOfPSN: %lu.", number.lowLongOfPSN);
847 ITDebugLog(@"Done getting iTunes' PSN.");
850 [(NSString *)name release];
853 ITDebugLog(@"Failed getting iTunes' PSN.");
857 - (NSString*)formatTimeInSeconds:(long)seconds {
858 long final = seconds;
859 NSString *finalString;
862 finalString = [NSString stringWithFormat:@"%i:%@:%@",(final / 3600),[self zeroSixty:(int)((final % 3600) / 60)],[self zeroSixty:(int)((final % 3600) % 60)]];
864 finalString = [NSString stringWithFormat:@"%i:%@",(final / 60),[self zeroSixty:(int)(final % 60)]];
867 finalString = [NSString stringWithFormat:@"0:%@",[self zeroSixty:(int)final]];
871 - (NSString*)zeroSixty:(int)seconds {
872 if ( (seconds < 10) && (seconds > 0) ) {
873 return [NSString stringWithFormat:@"0%i",seconds];
874 } else if ( (seconds == 0) ) {
875 return [NSString stringWithFormat:@"00"];
877 return [NSString stringWithFormat:@"%i",seconds];