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 [allSources release];
172 ITDebugLog(@"No sources.");
176 for (k = 1; k <= numSources ; k++) {
177 SInt32 numPlaylists = [ITSendAEWithString([NSString stringWithFormat:@"kocl:type('cPly'), '----':obj { form:'indx', want:type('cSrc'), seld:long(%u), from:() }",k], 'core', 'cnte', &savedPSN) int32Value];
178 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];
179 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];
180 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];
183 NSMutableArray *aSource = [[NSMutableArray alloc] init];
184 [aSource addObject:sourceName];
187 class = ITMTRemoteRadioSource;
190 class = ITMTRemoteGenericDeviceSource;
193 class = ITMTRemoteiPodSource;
197 class = ITMTRemoteCDSource;
200 class = ITMTRemoteSharedLibrarySource;
205 class = ITMTRemoteLibrarySource;
208 ITDebugLog(@"Adding source %@ of type %i at index %i", sourceName, class, index);
209 [aSource addObject:[NSNumber numberWithInt:class]];
210 [aSource addObject:[NSNumber numberWithInt:index]];
211 for (i = 1; i <= numPlaylists; i++) {
212 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];
213 NSString *theObj = [ITSendAEWithString(sendStr, 'core', 'getd', &savedPSN) stringValue];
214 ITDebugLog(@" - Adding playlist %@", theObj);
216 [aSource addObject:theObj];
219 [allSources addObject:[aSource autorelease]];
221 ITDebugLog(@"Source at index %i disappeared.", k);
224 ITDebugLog(@"Finished getting playlists.");
225 return [allSources autorelease];
230 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);
232 NSMutableArray *array = [[NSMutableArray alloc] init];
233 NSArray *returnArray;
234 for (i = 1; i <= [rawr numberOfItems]; i++) {
235 NSString *artist = [[rawr descriptorAtIndex:i] stringValue];
236 if (artist && [artist length] && ![array containsObject:artist]) {
237 [array addObject:artist];
240 [array sortUsingSelector:@selector(caseInsensitiveCompare:)];
241 returnArray = [NSArray arrayWithArray:array];
248 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);
250 NSMutableArray *array = [[NSMutableArray alloc] init];
251 NSArray *returnArray;
252 for (i = 1; i <= [rawr numberOfItems]; i++) {
253 NSString *album = [[rawr descriptorAtIndex:i] stringValue];
254 if (album && [album length] && ![array containsObject:album]) {
255 [array addObject:album];
258 [array sortUsingSelector:@selector(caseInsensitiveCompare:)];
259 returnArray = [NSArray arrayWithArray:array];
264 - (int)numberOfSongsInPlaylistAtIndex:(int)index
267 This method only returns the proper number if there's something playing.
268 This is because it gets the container of the current playlist so that it
269 gets the playlist index from the current source. Operating this way is fine,
270 since MT only ever calls this method when there is something playlist.
271 A working version of this that works in just the main source is in the
272 makePlaylistWithTerm:ofType: method.
275 NSAppleEventDescriptor *result;
276 ITDebugLog(@"Getting number of songs in playlist at index %i", index);
277 result = 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);
278 temp1 = (result == nil) ? -1 : (int)[result int32Value];
279 ITDebugLog(@"Getting number of songs in playlist at index %i done", index);
283 - (ITMTRemotePlayerSource)currentSource
287 ITDebugLog(@"Getting current source.");
289 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];
293 ITDebugLog(@"Getting current source done. Source: Radio.");
294 return ITMTRemoteRadioSource;
297 ITDebugLog(@"Getting current source done. Source: Generic Device.");
298 return ITMTRemoteGenericDeviceSource;
300 ITDebugLog(@"Getting current source done. Source: iPod.");
301 return ITMTRemoteiPodSource; //this is stupid
305 ITDebugLog(@"Getting current source done. Source: CD.");
306 return ITMTRemoteCDSource;
309 ITDebugLog(@"Getting current source done. Source: Shared Library.");
310 return ITMTRemoteSharedLibrarySource;
315 ITDebugLog(@"Getting current source done. Source: Library.");
316 return ITMTRemoteLibrarySource;
321 - (int)currentSourceIndex
323 ITDebugLog(@"Getting current source.");
324 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];
327 - (ITMTRemotePlayerPlaylistClass)currentPlaylistClass
330 ITDebugLog(@"Getting current playlist class");
331 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];
335 ITDebugLog(@"Getting current playlist class done. Class: Library.");
336 return ITMTRemotePlayerLibraryPlaylist;
339 ITDebugLog(@"Getting current playlist class done. Class: Radio.");
340 return ITMTRemotePlayerRadioPlaylist;
343 ITDebugLog(@"Getting current playlist class done. Class: Standard playlist.");
344 return ITMTRemotePlayerPlaylist;
348 - (int)currentPlaylistIndex
351 ITDebugLog(@"Getting current playlist index.");
352 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];
353 ITDebugLog(@"Getting current playlist index done.");
357 - (NSString *)songTitleAtIndex:(int)index
360 ITDebugLog(@"Getting song title at index %i.", index);
361 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];
362 ITDebugLog(@"Getting song title at index %i done.", index);
363 return ( ([temp1 length]) ? temp1 : nil ) ;
366 - (int)currentAlbumTrackCount
369 ITDebugLog(@"Getting current album track count.");
370 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];
371 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { temp1 = 0; }
372 ITDebugLog(@"Getting current album track count done.");
376 - (int)currentSongTrack
379 ITDebugLog(@"Getting current song track.");
380 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];
381 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { temp1 = 0; }
382 ITDebugLog(@"Getting current song track done.");
386 - (NSString *)playerStateUniqueIdentifier
389 ITDebugLog(@"Getting current unique identifier.");
390 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);
391 if (descriptor == nil) {
394 SInt32 cls = [descriptor int32Value];
395 if ( ([self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist) || (cls == 'cURT') ) {
396 NSString *bad = [NSString stringWithUTF8String:"浳湧"];
397 temp1 = [ITSendAEWithKey('pStT', 'core', 'getd', &savedPSN) stringValue];
398 if ([temp1 isEqualToString:bad]) {
399 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];
402 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]];
404 ITDebugLog(@"Getting current unique identifier done.");
405 return ( ([temp1 length]) ? temp1 : nil ) ;
408 - (int)currentSongIndex
411 ITDebugLog(@"Getting current song index.");
412 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];
413 ITDebugLog(@"Getting current song index done.");
417 - (NSString *)currentSongTitle
420 ITDebugLog(@"Getting current song title.");
422 //If we're listening to the radio.
423 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') {
424 NSString *bad = [NSString stringWithUTF8String:"浳湧"];
425 temp1 = [ITSendAEWithKey('pStT', 'core', 'getd', &savedPSN) stringValue];
426 if ([temp1 isEqualToString:bad]) {
427 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];
429 temp1 = [temp1 stringByAppendingString:@" (Stream)"];
431 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];
433 ITDebugLog(@"Getting current song title done.");
434 return ( ([temp1 length]) ? temp1 : nil ) ;
437 - (NSString *)currentSongArtist
440 ITDebugLog(@"Getting current song artist.");
441 if ( [self currentPlaylistClass] != ITMTRemotePlayerRadioPlaylist ) {
442 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];
446 ITDebugLog(@"Getting current song artist done.");
447 return ( ([temp1 length]) ? temp1 : nil ) ;
450 - (NSString *)currentSongComposer
453 ITDebugLog(@"Getting current song artist.");
454 if ( [self currentPlaylistClass] != ITMTRemotePlayerRadioPlaylist ) {
455 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];
459 ITDebugLog(@"Getting current song artist done.");
460 return ( ([temp1 length]) ? temp1 : nil ) ;
463 - (NSString *)currentSongAlbum
466 ITDebugLog(@"Getting current song album.");
467 if ( [self currentPlaylistClass] != ITMTRemotePlayerRadioPlaylist ) {
468 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];
472 ITDebugLog(@"Getting current song album done.");
473 return ( ([temp1 length]) ? temp1 : nil ) ;
476 - (NSString *)currentSongGenre
479 ITDebugLog(@"Getting current song genre.");
480 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];
481 ITDebugLog(@"Getting current song genre done.");
482 return ( ([temp1 length]) ? temp1 : nil ) ;
485 - (NSString *)currentSongLength
489 ITDebugLog(@"Getting current song length.");
490 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];
491 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];
492 if ( ([self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist) || (temp1 == 'cURT') ) { temp2 = @"Continuous"; }
493 ITDebugLog(@"Getting current song length done.");
497 - (NSString *)currentSongRemaining
499 SInt32 duration, current, final;
500 NSString *finalString;
502 ITDebugLog(@"Getting current song remaining time.");
504 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];
505 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];
506 final = duration - current;
507 finalString = [self formatTimeInSeconds:final];
509 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { finalString = nil; }
511 ITDebugLog(@"Getting current song remaining time done.");
516 - (NSString *)currentSongElapsed
519 NSString *finalString;
521 ITDebugLog(@"Getting current song elapsed time.");
522 final = (long)[ITSendAEWithKey('pPos', 'core', 'getd', &savedPSN) int32Value];
523 finalString = [self formatTimeInSeconds:final];
524 ITDebugLog(@"Getting current song elapsed time done.");
528 - (NSImage *)currentSongAlbumArt
530 ITDebugLog(@"Getting current song album art.");
531 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];
532 ITDebugLog(@"Getting current song album art done.");
534 return [[[NSImage alloc] initWithData:data] autorelease];
540 - (int)currentSongPlayCount
543 ITDebugLog(@"Getting current song play count.");
544 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];
545 ITDebugLog(@"Getting current song play count done.");
549 - (float)currentSongRating
552 ITDebugLog(@"Getting current song rating.");
553 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);
554 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { temp1 = -1.0; }
555 ITDebugLog(@"Getting current song rating done.");
559 - (BOOL)setCurrentSongRating:(float)rating
561 ITDebugLog(@"Setting current song rating to %f.", rating);
562 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { return NO; }
563 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);
564 ITDebugLog(@"Setting current song rating to %f done.", rating);
568 - (BOOL)equalizerEnabled
570 ITDebugLog(@"Getting equalizer enabled status.");
571 int thingy = (int)[ITSendAEWithKey('pEQ ', 'core', 'getd', &savedPSN) int32Value];
572 ITDebugLog(@"Done getting equalizer enabled status.");
573 return (thingy != 0) ? YES : NO;
576 - (BOOL)setEqualizerEnabled:(BOOL)enabled
578 ITDebugLog(@"Setting equalizer enabled to %i.", enabled);
579 ITSendAEWithString([NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pEQ '), from:'null'() }", enabled], 'core', 'setd', &savedPSN);
580 ITDebugLog(@"Done setting equalizer enabled to %i.", enabled);
584 - (NSArray *)eqPresets
587 SInt32 numPresets = [ITSendAEWithString(@"kocl:type('cEQP'), '----':(), &subj:()", 'core', 'cnte', &savedPSN) int32Value];
588 NSMutableArray *presets = [[NSMutableArray alloc] initWithCapacity:numPresets];
589 ITDebugLog(@"Getting EQ presets");
590 for (i = 1; i <= numPresets; i++) {
591 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];
593 ITDebugLog(@"Adding preset %@", theObj);
594 [presets addObject:theObj];
597 ITDebugLog(@"Done getting EQ presets");
598 return [presets autorelease];
601 - (int)currentEQPresetIndex
604 ITDebugLog(@"Getting current EQ preset index.");
605 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];
606 ITDebugLog(@"Getting current EQ preset index done.");
612 ITDebugLog(@"Getting volume.");
613 ITDebugLog(@"Getting volume done.");
614 return (float)[ITSendAEWithKey('pVol', 'core', 'getd', &savedPSN) int32Value] / 100;
617 - (BOOL)setVolume:(float)volume
619 ITDebugLog(@"Setting volume to %f.", volume);
620 ITSendAEWithString([NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pVol'), from:'null'() }", (long)(volume * 100)], 'core', 'setd', &savedPSN);
621 ITDebugLog(@"Setting volume to %f done.", volume);
625 - (BOOL)shuffleEnabled
627 ITDebugLog(@"Getting shuffle enabled status.");
629 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];
635 ITDebugLog(@"Getting shuffle enabled status done.");
639 - (BOOL)setShuffleEnabled:(BOOL)enabled
641 ITDebugLog(@"Set shuffle enabled to %i", enabled);
642 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);
643 ITDebugLog(@"Set shuffle enabled to %i done", enabled);
647 - (ITMTRemotePlayerRepeatMode)repeatMode
649 FourCharCode m00f = 0;
651 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];
652 ITDebugLog(@"Getting repeat mode.");
657 ITDebugLog(@"Repeat off");
658 result = ITMTRemotePlayerRepeatOff;
661 ITDebugLog(@"Repeat one");
662 result = ITMTRemotePlayerRepeatOne;
665 ITDebugLog(@"Repeat all");
666 result = ITMTRemotePlayerRepeatAll;
669 ITDebugLog(@"Getting repeat mode done.");
673 - (BOOL)setRepeatMode:(ITMTRemotePlayerRepeatMode)repeatMode
676 ITDebugLog(@"Setting repeat mode to %i", repeatMode);
679 case ITMTRemotePlayerRepeatOne:
682 case ITMTRemotePlayerRepeatAll:
685 case ITMTRemotePlayerRepeatOff:
690 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);
691 ITDebugLog(@"Setting repeat mode to %c done", m00f);
698 ITSendAE('hook', 'Play', &savedPSN);
699 ITDebugLog(@"Play done");
705 ITDebugLog(@"Pause");
706 ITSendAE('hook', 'Paus', &savedPSN);
707 ITDebugLog(@"Pause done");
713 ITDebugLog(@"Go to next track");
714 ITSendAE('hook', 'Next', &savedPSN);
715 ITDebugLog(@"Go to next track done");
719 - (BOOL)goToPreviousSong
721 ITDebugLog(@"Go to previous track");
722 ITSendAE('hook', 'Prev', &savedPSN);
723 ITDebugLog(@"Go to previous track done");
729 ITDebugLog(@"Fast forward action");
730 ITSendAE('hook', 'Fast', &savedPSN);
731 ITDebugLog(@"Fast forward action done");
737 ITDebugLog(@"Rewind action");
738 ITSendAE('hook', 'Rwnd', &savedPSN);
739 ITDebugLog(@"Rewind action done");
743 - (BOOL)switchToPlaylistAtIndex:(int)index
745 ITDebugLog(@"Switching to playlist at index %i", index);
746 ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:() }", index], 'hook', 'Play', &savedPSN);
747 ITDebugLog(@"Done switching to playlist at index %i", index);
751 - (BOOL)switchToPlaylistAtIndex:(int)index ofSourceAtIndex:(int)index2
753 ITDebugLog(@"Switching to playlist at index %i of source %i", index, index2);
754 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);
755 ITDebugLog(@"Done switching to playlist at index %i of source %i", index, index2);
759 - (BOOL)switchToSongAtIndex:(int)index
761 ITDebugLog(@"Switching to track at index %i", index);
762 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);
763 ITDebugLog(@"Done switching to track at index %i", index);
767 - (BOOL)switchToEQAtIndex:(int)index
769 ITDebugLog(@"Switching to EQ preset at index %i", index);
770 // index should count from 0, but itunes counts from 1, so let's add 1.
771 [self setEqualizerEnabled:YES];
772 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);
773 ITDebugLog(@"Done switching to EQ preset at index %i", index);
777 - (BOOL)makePlaylistWithTerm:(NSString *)term ofType:(int)type
781 //Get fixed indexing status
782 BOOL fixed = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pFix'), from:'null'() }", 'core', 'getd', &savedPSN) booleanValue];
784 //Enabled fixed indexing
785 ITSendAEWithString(@"data:long(1), '----':obj { form:'prop', want:type('prop'), seld:type('pFix'), from:'null'() }", 'core', 'setd', &savedPSN);
787 //Search for the term
788 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);
790 //If MenuTunes playlist exists
791 if ([ITSendAEWithString(@"'----':obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", 'core', 'doex', &savedPSN) booleanValue]) {
792 //Clear old MenuTunes playlist
793 int numSongs = [ITSendAEWithString(@"kocl:type('cTrk'), '----':obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", 'core', 'cnte', &savedPSN) int32Value];
794 for (i = 1; i <= numSongs; i++) {
795 ITSendAEWithString(@"'----':obj { form:'indx', want:type('cTrk'), seld:long(1), from:obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() } }", 'core', 'delo', &savedPSN);
798 //Create MenuTunes playlist
799 ITSendAEWithString(@"prdt:{ pnam:\"MenuTunes\" }, kocl:type('cPly'), &subj:()", 'core', 'crel', &savedPSN);
802 //Duplicate search results to playlist
803 for (i = 1; i <= [searchResults numberOfItems]; i++) {
804 ITSendAEWithStringAndObject(@"insh:obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", [[searchResults descriptorAtIndex:i] aeDesc], 'core', 'clon', &savedPSN);
806 //Reset fixed indexing
807 ITSendAEWithString([NSString stringWithFormat:@"data:long(%i), '----':obj { form:'prop', want:type('prop'), seld:type('pFix'), from:'null'() }", fixed], 'core', 'setd', &savedPSN);
809 //Play MenuTunes playlist
810 ITSendAEWithString(@"'----':obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", 'hook', 'Play', &savedPSN);
815 - (ProcessSerialNumber)iTunesPSN
817 /*NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
818 ProcessSerialNumber number;
820 int count = [apps count];
822 number.highLongOfPSN = kNoProcess;
824 for (i = 0; i < count; i++)
826 NSDictionary *curApp = [apps objectAtIndex:i];
828 if ([[curApp objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"])
830 number.highLongOfPSN = [[curApp objectForKey:
831 @"NSApplicationProcessSerialNumberHigh"] intValue];
832 number.lowLongOfPSN = [[curApp objectForKey:
833 @"NSApplicationProcessSerialNumberLow"] intValue];
837 ProcessSerialNumber number;
838 number.highLongOfPSN = kNoProcess;
839 number.lowLongOfPSN = 0;
840 ITDebugLog(@"Getting iTunes' PSN.");
841 while ( (GetNextProcess(&number) == noErr) )
844 if ( (CopyProcessName(&number, &name) == noErr) )
846 if ([(NSString *)name isEqualToString:@"iTunes"])
848 ITDebugLog(@"iTunes' highLPongOfPSN: %lu.", number.highLongOfPSN);
849 ITDebugLog(@"iTunes' lowLongOfPSN: %lu.", number.lowLongOfPSN);
850 ITDebugLog(@"Done getting iTunes' PSN.");
853 [(NSString *)name release];
856 ITDebugLog(@"Failed getting iTunes' PSN.");
860 - (NSString*)formatTimeInSeconds:(long)seconds {
861 long final = seconds;
862 NSString *finalString;
865 finalString = [NSString stringWithFormat:@"%i:%@:%@",(final / 3600),[self zeroSixty:(int)((final % 3600) / 60)],[self zeroSixty:(int)((final % 3600) % 60)]];
867 finalString = [NSString stringWithFormat:@"%i:%@",(final / 60),[self zeroSixty:(int)(final % 60)]];
870 finalString = [NSString stringWithFormat:@"0:%@",[self zeroSixty:(int)final]];
874 - (NSString*)zeroSixty:(int)seconds {
875 if ( (seconds < 10) && (seconds > 0) ) {
876 return [NSString stringWithFormat:@"0%i",seconds];
877 } else if ( (seconds == 0) ) {
878 return [NSString stringWithFormat:@"00"];
880 return [NSString stringWithFormat:@"%i",seconds];