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:long(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:long(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:long(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 = ([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';
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 = ([self isPlaying] ? [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] : -1);
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) || ([descriptor int32Value] == 'prop')) {
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 = ([self isPlaying] ? [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] : -1);
413 ITDebugLog(@"Getting current song index done.");
417 - (NSString *)currentSongTitle
420 ITDebugLog(@"Getting current song title.");
421 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];
423 //If we're listening to the radio.
424 if (result == 'cURT') {
425 NSString *bad = [NSString stringWithUTF8String:"浳湧"];
426 temp1 = [ITSendAEWithKey('pStT', 'core', 'getd', &savedPSN) stringValue];
427 if ([temp1 isEqualToString:bad]) {
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 temp1 = [temp1 stringByAppendingString:@" (Stream)"];
431 } else if (result == 'prop') {
434 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];
436 ITDebugLog(@"Getting current song title done.");
437 return ( ([temp1 length]) ? temp1 : nil ) ;
440 - (NSString *)currentSongArtist
443 ITDebugLog(@"Getting current song artist.");
444 if ( [self currentPlaylistClass] != ITMTRemotePlayerRadioPlaylist ) {
445 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];
449 ITDebugLog(@"Getting current song artist done.");
450 return ( ([temp1 length]) ? temp1 : nil ) ;
453 - (NSString *)currentSongComposer
456 ITDebugLog(@"Getting current song artist.");
457 if ( [self currentPlaylistClass] != ITMTRemotePlayerRadioPlaylist ) {
458 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];
462 ITDebugLog(@"Getting current song artist done.");
463 return ( ([temp1 length]) ? temp1 : nil ) ;
466 - (NSString *)currentSongAlbum
469 ITDebugLog(@"Getting current song album.");
470 if ( [self currentPlaylistClass] != ITMTRemotePlayerRadioPlaylist ) {
471 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];
475 ITDebugLog(@"Getting current song album done.");
476 return ( ([temp1 length]) ? temp1 : nil ) ;
479 - (NSString *)currentSongGenre
482 ITDebugLog(@"Getting current song genre.");
483 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];
484 ITDebugLog(@"Getting current song genre done.");
485 return ( ([temp1 length]) ? temp1 : nil ) ;
488 - (NSString *)currentSongLength
492 ITDebugLog(@"Getting current song length.");
493 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];
494 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];
495 if ( ([self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist) || (temp1 == 'cURT') ) { temp2 = @"Continuous"; }
496 ITDebugLog(@"Getting current song length done.");
500 - (NSString *)currentSongRemaining
502 SInt32 duration, current, final;
503 NSString *finalString;
505 ITDebugLog(@"Getting current song remaining time.");
507 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];
508 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];
509 final = duration - current;
510 finalString = [self formatTimeInSeconds:final];
512 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { finalString = nil; }
514 ITDebugLog(@"Getting current song remaining time done.");
519 - (NSString *)currentSongElapsed
522 NSString *finalString;
524 ITDebugLog(@"Getting current song elapsed time.");
525 final = (long)[ITSendAEWithKey('pPos', 'core', 'getd', &savedPSN) int32Value];
526 finalString = [self formatTimeInSeconds:final];
527 ITDebugLog(@"Getting current song elapsed time done.");
531 - (NSImage *)currentSongAlbumArt
533 ITDebugLog(@"Getting current song album art.");
534 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;
535 ITDebugLog(@"Getting current song album art done.");
537 return [[[NSImage alloc] initWithData:data] autorelease];
543 - (int)currentSongPlayCount
546 ITDebugLog(@"Getting current song play count.");
547 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];
548 ITDebugLog(@"Getting current song play count done.");
552 - (float)currentSongRating
555 ITDebugLog(@"Getting current song rating.");
556 temp1 = (![self isPlaying] || ([self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist)) ? -1.0 : ((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);
557 ITDebugLog(@"Getting current song rating done.");
561 - (BOOL)setCurrentSongRating:(float)rating
563 ITDebugLog(@"Setting current song rating to %f.", rating);
564 if ( [self currentPlaylistClass] == ITMTRemotePlayerRadioPlaylist ) { return NO; }
565 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);
566 ITDebugLog(@"Setting current song rating to %f done.", rating);
570 - (BOOL)equalizerEnabled
572 ITDebugLog(@"Getting equalizer enabled status.");
573 int thingy = (int)[ITSendAEWithKey('pEQ ', 'core', 'getd', &savedPSN) int32Value];
574 ITDebugLog(@"Done getting equalizer enabled status.");
575 return (thingy != 0) ? YES : NO;
578 - (BOOL)setEqualizerEnabled:(BOOL)enabled
580 ITDebugLog(@"Setting equalizer enabled to %i.", enabled);
581 ITSendAEWithString([NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pEQ '), from:'null'() }", enabled], 'core', 'setd', &savedPSN);
582 ITDebugLog(@"Done setting equalizer enabled to %i.", enabled);
586 - (NSArray *)eqPresets
589 SInt32 numPresets = [ITSendAEWithString(@"kocl:type('cEQP'), '----':(), &subj:()", 'core', 'cnte', &savedPSN) int32Value];
590 NSMutableArray *presets = [[NSMutableArray alloc] initWithCapacity:numPresets];
591 ITDebugLog(@"Getting EQ presets");
592 for (i = 1; i <= numPresets; i++) {
593 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];
595 ITDebugLog(@"Adding preset %@", theObj);
596 [presets addObject:theObj];
599 ITDebugLog(@"Done getting EQ presets");
600 return [presets autorelease];
603 - (int)currentEQPresetIndex
606 ITDebugLog(@"Getting current EQ preset index.");
607 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];
608 ITDebugLog(@"Getting current EQ preset index done.");
614 ITDebugLog(@"Getting volume.");
615 ITDebugLog(@"Getting volume done.");
616 return (float)[ITSendAEWithKey('pVol', 'core', 'getd', &savedPSN) int32Value] / 100;
619 - (BOOL)setVolume:(float)volume
621 ITDebugLog(@"Setting volume to %f.", volume);
622 ITSendAEWithString([NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pVol'), from:'null'() }", (long)(volume * 100)], 'core', 'setd', &savedPSN);
623 ITDebugLog(@"Setting volume to %f done.", volume);
627 - (BOOL)shuffleEnabled
629 ITDebugLog(@"Getting shuffle enabled status.");
631 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];
637 ITDebugLog(@"Getting shuffle enabled status done.");
641 - (BOOL)setShuffleEnabled:(BOOL)enabled
643 ITDebugLog(@"Set shuffle enabled to %i", enabled);
644 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);
645 ITDebugLog(@"Set shuffle enabled to %i done", enabled);
649 - (ITMTRemotePlayerRepeatMode)repeatMode
651 FourCharCode m00f = 0;
653 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];
654 ITDebugLog(@"Getting repeat mode.");
659 ITDebugLog(@"Repeat off");
660 result = ITMTRemotePlayerRepeatOff;
663 ITDebugLog(@"Repeat one");
664 result = ITMTRemotePlayerRepeatOne;
667 ITDebugLog(@"Repeat all");
668 result = ITMTRemotePlayerRepeatAll;
671 ITDebugLog(@"Getting repeat mode done.");
675 - (BOOL)setRepeatMode:(ITMTRemotePlayerRepeatMode)repeatMode
678 ITDebugLog(@"Setting repeat mode to %i", repeatMode);
681 case ITMTRemotePlayerRepeatOne:
684 case ITMTRemotePlayerRepeatAll:
687 case ITMTRemotePlayerRepeatOff:
692 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);
693 ITDebugLog(@"Setting repeat mode to %c done", m00f);
700 ITSendAE('hook', 'Play', &savedPSN);
701 ITDebugLog(@"Play done");
707 ITDebugLog(@"Pause");
708 ITSendAE('hook', 'Paus', &savedPSN);
709 ITDebugLog(@"Pause done");
715 ITDebugLog(@"Go to next track");
716 ITSendAE('hook', 'Next', &savedPSN);
717 ITDebugLog(@"Go to next track done");
721 - (BOOL)goToPreviousSong
723 ITDebugLog(@"Go to previous track");
724 ITSendAE('hook', 'Back', &savedPSN);
725 ITDebugLog(@"Go to previous track done");
731 ITDebugLog(@"Fast forward action");
732 ITSendAE('hook', 'Fast', &savedPSN);
733 ITDebugLog(@"Fast forward action done");
739 ITDebugLog(@"Rewind action");
740 ITSendAE('hook', 'Rwnd', &savedPSN);
741 ITDebugLog(@"Rewind action done");
745 - (BOOL)switchToPlaylistAtIndex:(int)index
747 ITDebugLog(@"Switching to playlist at index %i", index);
748 ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:() }", index], 'hook', 'Play', &savedPSN);
749 ITDebugLog(@"Done switching to playlist at index %i", index);
753 - (BOOL)switchToPlaylistAtIndex:(int)index ofSourceAtIndex:(int)index2
755 ITDebugLog(@"Switching to playlist at index %i of source %i", index, index2);
756 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);
757 ITDebugLog(@"Done switching to playlist at index %i of source %i", index, index2);
761 - (BOOL)switchToSongAtIndex:(int)index
763 ITDebugLog(@"Switching to track at index %i", index);
764 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);
765 ITDebugLog(@"Done switching to track at index %i", index);
769 - (BOOL)switchToEQAtIndex:(int)index
771 ITDebugLog(@"Switching to EQ preset at index %i", index);
772 // index should count from 0, but itunes counts from 1, so let's add 1.
773 [self setEqualizerEnabled:YES];
774 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);
775 ITDebugLog(@"Done switching to EQ preset at index %i", index);
779 - (BOOL)makePlaylistWithTerm:(NSString *)term ofType:(int)type
783 //Get fixed indexing status
784 BOOL fixed = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pFix'), from:'null'() }", 'core', 'getd', &savedPSN) booleanValue];
786 //Enabled fixed indexing
787 ITSendAEWithString(@"data:long(1), '----':obj { form:'prop', want:type('prop'), seld:type('pFix'), from:'null'() }", 'core', 'setd', &savedPSN);
789 //Search for the term
790 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);
792 //If MenuTunes playlist exists
793 if ([ITSendAEWithString(@"'----':obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", 'core', 'doex', &savedPSN) booleanValue]) {
794 //Clear old MenuTunes playlist
795 int numSongs = [ITSendAEWithString(@"kocl:type('cTrk'), '----':obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", 'core', 'cnte', &savedPSN) int32Value];
796 for (i = 1; i <= numSongs; i++) {
797 ITSendAEWithString(@"'----':obj { form:'indx', want:type('cTrk'), seld:long(1), from:obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() } }", 'core', 'delo', &savedPSN);
800 //Create MenuTunes playlist
801 ITSendAEWithString(@"prdt:{ pnam:\"MenuTunes\" }, kocl:type('cPly'), &subj:()", 'core', 'crel', &savedPSN);
804 //Duplicate search results to playlist
805 for (i = 1; i <= [searchResults numberOfItems]; i++) {
806 ITSendAEWithStringAndObject(@"insh:obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", [[searchResults descriptorAtIndex:i] aeDesc], 'core', 'clon', &savedPSN);
808 //Reset fixed indexing
809 ITSendAEWithString([NSString stringWithFormat:@"data:long(%i), '----':obj { form:'prop', want:type('prop'), seld:type('pFix'), from:'null'() }", fixed], 'core', 'setd', &savedPSN);
811 //Play MenuTunes playlist
812 ITSendAEWithString(@"'----':obj { form:'name', want:type('cPly'), seld:\"MenuTunes\", from:'null'() }", 'hook', 'Play', &savedPSN);
819 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');
822 - (ProcessSerialNumber)iTunesPSN
824 /*NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
825 ProcessSerialNumber number;
827 int count = [apps count];
829 number.highLongOfPSN = kNoProcess;
831 for (i = 0; i < count; i++)
833 NSDictionary *curApp = [apps objectAtIndex:i];
835 if ([[curApp objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"])
837 number.highLongOfPSN = [[curApp objectForKey:
838 @"NSApplicationProcessSerialNumberHigh"] intValue];
839 number.lowLongOfPSN = [[curApp objectForKey:
840 @"NSApplicationProcessSerialNumberLow"] intValue];
844 ProcessSerialNumber number;
845 number.highLongOfPSN = kNoProcess;
846 number.lowLongOfPSN = 0;
847 ITDebugLog(@"Getting iTunes' PSN.");
848 while ( (GetNextProcess(&number) == noErr) )
851 if ( (CopyProcessName(&number, &name) == noErr) )
853 if ([(NSString *)name isEqualToString:@"iTunes"])
855 ITDebugLog(@"iTunes' highLPongOfPSN: %lu.", number.highLongOfPSN);
856 ITDebugLog(@"iTunes' lowLongOfPSN: %lu.", number.lowLongOfPSN);
857 ITDebugLog(@"Done getting iTunes' PSN.");
860 [(NSString *)name release];
863 ITDebugLog(@"Failed getting iTunes' PSN.");
867 - (NSString*)formatTimeInSeconds:(long)seconds {
868 long final = seconds;
869 NSString *finalString;
872 finalString = [NSString stringWithFormat:@"%i:%@:%@",(final / 3600),[self zeroSixty:(int)((final % 3600) / 60)],[self zeroSixty:(int)((final % 3600) % 60)]];
874 finalString = [NSString stringWithFormat:@"%i:%@",(final / 60),[self zeroSixty:(int)(final % 60)]];
877 finalString = [NSString stringWithFormat:@"0:%@",[self zeroSixty:(int)final]];
881 - (NSString*)zeroSixty:(int)seconds {
882 if ( (seconds < 10) && (seconds > 0) ) {
883 return [NSString stringWithFormat:@"0%i",seconds];
884 } else if ( (seconds == 0) ) {
885 return [NSString stringWithFormat:@"00"];
887 return [NSString stringWithFormat:@"%i",seconds];