Update iTunesRemote to match the new API. MainController and
[MenuTunes.git] / iTunesRemote.m
1 #import "iTunesRemote.h"
2
3 @implementation iTunesRemote
4
5 + (id)remote
6 {
7     return [[[iTunesRemote alloc] init] autorelease];
8 }
9
10 //What should this do?
11 - (NSString *)informationString:(ITMTRemoteInformationString)string
12 {
13     return @"";
14 }
15
16 - (NSImage *)icon
17 {
18     return nil;
19 }
20
21 - (BOOL)begin
22 {
23     savedPSN = [self iTunesPSN];
24     return YES;
25 }
26
27 - (BOOL)halt
28 {
29     return YES;
30 }
31
32 - (BOOL)supportsControlAction:(ITMTRemoteControlAction)action
33 {
34     switch (action)
35     {
36         case ITMTRemoteStop:
37         case ITMTRemotePause:
38         case ITMTRemotePlay:
39         case ITMTRemoteRewind:
40         case ITMTRemoteFastForward:
41         case ITMTRemotePreviousTrack:
42         case ITMTRemoteNextTrack:
43             return YES;
44         break;
45         default:
46             return NO;
47         break;
48     }
49 }
50
51 - (BOOL)sendControlAction:(ITMTRemoteControlAction)action
52 {
53     NSString *eventID;
54     switch (action)
55     {
56         case ITMTRemoteStop:
57             eventID = @"Stop";
58             return NO;
59         break;
60         case ITMTRemotePause:
61             eventID = @"Paus";
62         break;
63         case ITMTRemotePlay:
64             eventID = @"Play";
65         break;
66         case ITMTRemoteRewind:
67             eventID = @"Rwnd";
68         break;
69         case ITMTRemoteFastForward:
70             eventID = @"Fast";
71         break;
72         case ITMTRemotePreviousTrack:
73             eventID = @"Prev";
74         break;
75         case ITMTRemoteNextTrack:
76             eventID = @"Next";
77         break;
78         default:
79             return NO;
80         break;
81     }
82     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:eventID appPSN:savedPSN];
83     return YES;
84 }
85
86 - (ITMTRemoteControlState)controlState
87 {
88     long result = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"'----':obj { form:'prop', want:type('prop'), seld:type('pPlS'), from:'null'() }" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
89     
90     switch (result)
91     {
92         default:
93         case 'kPSS':
94             return ITMTRemotePlayerStopped;
95         case 'kPSP':
96             return ITMTRemotePlayerPlaying;
97         case 'kPSp':
98             return ITMTRemotePlayerPaused;
99         case 'kPSR':
100             return ITMTRemotePlayerRewinding;
101         case 'kPSF':
102             return ITMTRemotePlayerForwarding;
103     }
104     return ITMTRemotePlayerStopped;
105 }
106
107 - (ITMTRemotePlaylistMode)playlistMode
108 {
109     return ITMTRemoteLibraryAndPlaylists;
110 }
111
112 - (NSArray *)playlistNames
113 {
114     long i;
115     const signed long numPlaylists = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cPly'), '----':()" eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
116     NSMutableArray *playlists = [[NSMutableArray alloc] initWithCapacity:numPlaylists];
117     
118     for (i = 1; i <= numPlaylists; i++) {
119         const long j = i;
120         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];
121         NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:sendStr eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
122         [playlists addObject:theObj];
123     }
124     return [playlists autorelease];
125 }
126
127 - (BOOL)switchToPlaylist:(int)playlistIndex
128 {
129     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:() }",index] eventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
130     return YES;
131 }
132
133 - (BOOL)switchToTrackAtIndex:(int)index
134 {
135     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:() } }",index] eventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
136     return YES;
137 }
138
139 //What do this?
140 - (int)indexForTrack:(int)identifier inPlaylist:(int)playlistIndex
141 {
142     return 0;
143 }
144
145 //What do this?
146 - (int)identifierForTrackAtIndex:(int)index inPlaylist:(int)playlistIndex
147 {
148     return 0;
149 }
150
151 - (BOOL)supportsTrackProperty:(ITMTRemoteTrackProperty)property
152 {
153     switch (property)
154     {
155         case ITMTRemoteTrackName:
156         case ITMTRemoteTrackArtist:
157         case ITMTRemoteTrackAlbum:
158         case ITMTRemoteTrackComposer:
159         case ITMTRemoteTrackNumber:
160         case ITMTRemoteTrackTotal:
161         case ITMTRemoteTrackComment:
162         case ITMTRemoteTrackGenre:
163         case ITMTRemoteTrackYear:
164         case ITMTRemoteTrackRating:
165         case ITMTRemoteTrackArt:
166             return YES;
167         break;
168         default:
169             return NO;
170         break;
171     }
172 }
173
174 //Somebody else do this
175 - (id)trackProperty:(ITMTRemoteTrackProperty)property atIndex:(int)index
176 {
177     switch (property)
178     {
179         case ITMTRemoteTrackName:
180         break;
181         case ITMTRemoteTrackArtist:
182         break;
183         case ITMTRemoteTrackAlbum:
184         break;
185         case ITMTRemoteTrackComposer:
186         break;
187         case ITMTRemoteTrackNumber:
188         break;
189         case ITMTRemoteTrackTotal:
190         break;
191         case ITMTRemoteTrackComment:
192         break;
193         case ITMTRemoteTrackGenre:
194         break;
195         case ITMTRemoteTrackYear:
196         break;
197         case ITMTRemoteTrackRating:
198         break;
199         case ITMTRemoteTrackArt:
200         break;
201     }
202     return nil;
203 }
204
205 //Somebody else do this
206 - (BOOL)setTrackProperty:(ITMTRemoteTrackProperty)property toValue:(id)value atIndex:(int)index
207 {
208     switch (property)
209     {
210         case ITMTRemoteTrackName:
211         break;
212         case ITMTRemoteTrackArtist:
213         break;
214         case ITMTRemoteTrackAlbum:
215         break;
216         case ITMTRemoteTrackComposer:
217         break;
218         case ITMTRemoteTrackNumber:
219         break;
220         case ITMTRemoteTrackTotal:
221         break;
222         case ITMTRemoteTrackComment:
223         break;
224         case ITMTRemoteTrackGenre:
225         break;
226         case ITMTRemoteTrackYear:
227         break;
228         case ITMTRemoteTrackRating:
229         break;
230         case ITMTRemoteTrackArt:
231         break;
232     }
233     return NO;
234 }
235
236 - (BOOL)supportsShuffle
237 {
238     return YES;
239 }
240
241 //This doesn't work
242 - (BOOL)setShuffle:(BOOL)toggle
243 {
244     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[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)toggle] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
245     return YES;
246 }
247
248 - (BOOL)shuffle
249 {
250     int result = [[ITAppleEventCenter sharedCenter]
251                 sendTwoTierAEWithRequestedKeyForNumber:@"pShf" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
252     return result;
253 }
254
255 - (BOOL)supportsRepeatMode:(ITMTRemoteRepeatMode)repeatMode
256 {
257     switch (repeatMode)
258     {
259         case ITMTRemoteRepeatNone:
260         case ITMTRemoteRepeatAll:
261         case ITMTRemoteRepeatOne:
262             return YES;
263         break;
264         default:
265             return NO;
266         break;
267     }
268 }
269
270 - (BOOL)setRepeatMode:(ITMTRemoteRepeatMode)repeatMode
271 {
272     char *m00f = NULL;
273     switch (repeatMode)
274     {
275         case ITMTRemoteRepeatNone:
276             m00f = "kRp0";
277         break;
278         case ITMTRemoteRepeatOne:
279             m00f = "kRp1";
280         break;
281         case ITMTRemoteRepeatAll:
282             m00f = "kRpA";
283         break;
284     }
285     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:type('%s') ----:obj { form:'prop', want:type('pRpt'), seld:type('pShf'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }",m00f] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
286     return YES;
287 }
288
289 - (BOOL)repeatMode
290 {
291     FourCharCode m00f = 0;
292     int result = 0;
293     m00f = [[ITAppleEventCenter sharedCenter]
294                 sendTwoTierAEWithRequestedKeyForNumber:@"pRpt" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
295     
296     switch (m00f)
297     {
298         case 'kRp0':
299             result = ITMTRemoteRepeatNone;
300         break;
301         case 'kRp1':
302             result = ITMTRemoteRepeatOne;
303         break;
304         case 'kRpA':
305             result = ITMTRemoteRepeatAll;
306         break;
307     }
308     return result;
309 }
310
311 - (BOOL)supportsVolume
312 {
313     return YES;
314 }
315
316 - (BOOL)setVolume:(float)volume
317 {
318     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pVol'), from:'null'() }",(long)(volume*100)] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
319     return NO;
320 }
321
322 - (float)volume
323 {
324     return (float)[[ITAppleEventCenter sharedCenter] sendAEWithRequestedKeyForNumber:@"pVol" eventClass:@"core" eventID:@"getd" appPSN:savedPSN] / 100;
325 }
326
327 - (BOOL)supportsCustomEqualizer
328 {
329     return YES;
330 }
331
332 - (BOOL)showEqualizerWindow
333 {
334     //Do this Alex, please :D
335     return YES;
336 }
337
338 - (BOOL)supportsEqualizerPresets
339 {
340     return YES;
341 }
342
343 - (NSArray *)equalizerPresetNames
344 {
345     int i;
346     long numPresets = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cEQP'), '----':(), &subj:()" eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
347     NSMutableArray *presets = [[NSMutableArray alloc] initWithCapacity:numPresets];
348     
349     for (i = 1; i <= numPresets; i++) {
350         NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cEQP'), seld:long(%lu), from:'null'() } }",i] eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
351         if (theObj) {
352             [presets addObject:theObj];
353         }
354     }
355     return [presets autorelease];
356 }
357
358 - (BOOL)switchToEqualizerPreset:(int)index
359 {
360     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[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)] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
361     return YES;
362 }
363
364 - (BOOL)supportsExternalWindow
365 {
366     return YES;
367 }
368
369 - (NSString *)externalWindowName
370 {
371     return @"iTunes";
372 }
373
374 - (BOOL)showExternalWindow
375 {
376     //Do this Alex
377     return YES;
378 }
379
380 - (ProcessSerialNumber)iTunesPSN
381 {
382     ProcessSerialNumber number;
383     number.highLongOfPSN = kNoProcess;
384     number.lowLongOfPSN = 0;
385     
386     while ( (GetNextProcess(&number) == noErr) ) 
387     {
388         CFStringRef name;
389         if ( (CopyProcessName(&number, &name) == noErr) )
390         {
391             if ([(NSString *)name isEqualToString:@"iTunes"])
392             {
393                 return number;
394             }
395             [(NSString *)name release];
396         }
397     }
398     return number;
399 }
400
401 //Below is old
402 /*
403 + (id)remote
404 {
405     return [[[iTunesRemote alloc] init] autorelease];
406 }
407
408 - (NSString *)remoteTitle
409 {
410     return @"iTunes Remote";
411 }
412
413 - (NSString *)remoteInformation
414 {
415     return @"Default MenuTunes plugin to control iTunes, by iThink Software.";
416 }
417
418 - (NSImage *)remoteIcon
419 {
420     return nil;
421 }
422
423 - (BOOL)begin
424 {
425     savedPSN = [self iTunesPSN];
426     return YES;
427 }
428
429 - (BOOL)halt
430 {
431     return YES;
432 }
433
434 - (NSString *)playerFullName
435 {
436     return @"iTunes";
437 }
438
439 - (NSString *)playerSimpleName
440 {
441     return @"iTunes";
442 }
443
444 - (NSDictionary *)capabilities
445 {
446     return [NSDictionary dictionaryWithObjectsAndKeys:
447                 [NSNumber numberWithBool: YES], @"Remote",
448                 [NSNumber numberWithBool: YES], @"Basic Track Control",
449                 [NSNumber numberWithBool: YES], @"Track Information",
450                 [NSNumber numberWithBool: YES], @"Track Navigation",
451                 [NSNumber numberWithBool: YES], @"Upcoming Songs",
452                 [NSNumber numberWithBool: YES], @"Playlists",
453                 [NSNumber numberWithBool: YES], @"Volume",
454                 [NSNumber numberWithBool: YES], @"Shuffle",
455                 [NSNumber numberWithBool: YES], @"Repeat Modes",
456                 [NSNumber numberWithBool: YES], @"Equalizer",
457                 [NSNumber numberWithBool: YES], @"Track Rating",
458                 nil];
459 }
460
461 - (BOOL)showPrimaryInterface
462 {
463     // Make this into AppleEvents... shouldn't be too hard, I'm just too tired to do it right now.
464     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:@"data:long(1), '----':obj { form:'prop', want:type('prop'), seld:type('pisf'), from:'null'() }" eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
465     // Still have to convert these to AEs:
466     //  set visible of browser window 1 to true
467     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:@"data:long(1), ----:obj { form:'prop', want:'prop', seld:'pvis', from:obj { form:'indx', want:'cBrW', seld:1, from:'null'() } }" eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
468     //  set minimized of browser window 1 to false
469     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:@"data:long(0), ----:obj { form:'prop', want:'prop', seld:'pMin', from:obj { form:'indx', want:'cBrW', seld:1, from:'null'() } }" eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
470
471     return NO;
472 }
473
474 - (ITMTRemotePlayerRunningState)playerRunningState
475 {
476     NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
477     int i;
478     int count = [apps count];
479     
480     for (i = 0; i < count; i++) {
481         if ([[[apps objectAtIndex:i] objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) {
482             return ITMTRemotePlayerRunning;
483         }
484     }
485     return ITMTRemotePlayerNotRunning;
486 }
487
488 - (ITMTRemotePlayerPlayingState)playerPlayingState
489 {
490     long result = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"'----':obj { form:'prop', want:type('prop'), seld:type('pPlS'), from:'null'() }" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
491     
492     switch (result)
493     {
494         default:
495         case 'kPSS':
496             return ITMTRemotePlayerStopped;
497         case 'kPSP':
498             return ITMTRemotePlayerPlaying;
499         case 'kPSp':
500             return ITMTRemotePlayerPaused;
501         case 'kPSR':
502             return ITMTRemotePlayerRewinding;
503         case 'kPSF':
504             return ITMTRemotePlayerForwarding;
505     }
506     
507     return ITMTRemotePlayerStopped;
508 }
509
510 - (NSArray *)playlists
511 {
512     long i = 0;
513     const signed long numPlaylists = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cPly'), '----':()" eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
514     NSMutableArray *playlists = [[NSMutableArray alloc] initWithCapacity:numPlaylists];
515     
516     for (i = 1; i <= numPlaylists; i++) {
517         const long j = i;
518         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];
519         NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:sendStr eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
520         [playlists addObject:theObj];
521     }
522     return [playlists autorelease];
523 }
524
525 - (int)numberOfSongsInPlaylistAtIndex:(int)index
526 {
527     return [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:[NSString stringWithFormat:@"kocl:type('cTrk'), '----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:'null'() }",index] eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
528 }
529
530 - (ITMTRemotePlayerPlaylistClass)currentPlaylistClass
531 {
532     int realResult = [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pcls" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
533     
534
535     switch (realResult)
536            {
537            case 'cLiP':
538                   return ITMTRemotePlayerLibraryPlaylist;
539                   break;
540            case 'cRTP':
541                   return ITMTRemotePlayerRadioPlaylist;
542                   break;
543            default:
544                   return ITMTRemotePlayerPlaylist;
545            }
546 }
547
548 - (int)currentPlaylistIndex
549 {
550     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
551 }
552
553 - (NSString *)songTitleAtIndex:(int)index
554 {
555     return [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[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] eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
556 }
557
558 - (int)currentAlbumTrackCount
559 {
560     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pTrC" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
561 }
562
563 - (int)currentSongTrack
564 {
565     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pTrN" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
566 }
567
568 - (NSString *)currentSongUniqueIdentifier
569 {
570     return [NSString stringWithFormat:@"%i-%i", [self currentPlaylistIndex], [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pDID" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN]];
571 }
572
573 - (int)currentSongIndex
574 {
575     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
576 }
577
578 - (NSString *)currentSongTitle
579 {
580     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pnam" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
581 }
582
583 - (NSString *)currentSongArtist
584 {
585     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pArt" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
586 }
587
588 - (NSString *)currentSongAlbum
589 {
590     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pAlb" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
591 }
592
593 - (NSString *)currentSongGenre
594 {
595     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pGen" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
596 }
597
598 - (NSString *)currentSongLength
599 {
600     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pTim" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
601 }
602
603 - (NSString *)currentSongRemaining
604 {
605     long duration = [[ITAppleEventCenter sharedCenter]
606                         sendTwoTierAEWithRequestedKeyForNumber:@"pDur" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
607     long current = [[ITAppleEventCenter sharedCenter]
608                         sendAEWithRequestedKeyForNumber:@"pPos" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
609
610     return [[NSNumber numberWithLong:duration - current] stringValue];
611 }
612
613 - (float)currentSongRating
614 {
615     return (float)[[ITAppleEventCenter sharedCenter]
616                 sendTwoTierAEWithRequestedKeyForNumber:@"pRte" fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd" appPSN:savedPSN] / 100.0;
617 }
618
619 - (BOOL)setCurrentSongRating:(float)rating
620 {
621     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[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]] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
622     return YES;
623 }
624
625 /* - (BOOL)equalizerEnabled
626 {
627     int thingy = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"'----':obj { form:type('prop'), want:type('prop'), seld:type('pEQ '), from:() }" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
628     NSLog(@"Debug equalizerEnabled: %i", thingy);
629     return thingy;
630 }
631
632 - (BOOL)setEqualizerEnabled:(BOOL)enabled
633 {
634     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pEQ '), from:'null'() }",enabled] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
635     return YES;
636 } */
637
638 /*- (NSArray *)eqPresets
639 {
640     int i;
641     long numPresets = [[ITAppleEventCenter sharedCenter] sendAEWithSendStringForNumber:@"kocl:type('cEQP'), '----':(), &subj:()" eventClass:@"core" eventID:@"cnte" appPSN:savedPSN];
642     NSMutableArray *presets = [[NSMutableArray alloc] initWithCapacity:numPresets];
643     
644     for (i = 1; i <= numPresets; i++) {
645         NSString *theObj = [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('pnam'), from:obj { form:'indx', want:type('cEQP'), seld:long(%lu), from:'null'() } }",i] eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
646         if (theObj) {
647             [presets addObject:theObj];
648         }
649     }
650     return [presets autorelease];
651 }
652
653 - (int)currentEQPresetIndex
654 {
655     int result;
656     result = [[ITAppleEventCenter sharedCenter]
657                 sendTwoTierAEWithRequestedKeyForNumber:@"pidx" fromObjectByKey:@"pEQP" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
658     return result;
659 }
660
661 - (float)volume
662 {
663     return (float)[[ITAppleEventCenter sharedCenter] sendAEWithRequestedKeyForNumber:@"pVol" eventClass:@"core" eventID:@"getd" appPSN:savedPSN] / 100;
664 }
665
666 - (BOOL)setVolume:(float)volume
667 {
668     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:long(%lu), '----':obj { form:'prop', want:type('prop'), seld:type('pVol'), from:'null'() }",(long)(volume*100)] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
669     return NO;
670 }
671
672 - (BOOL)shuffleEnabled
673 {
674     int result = [[ITAppleEventCenter sharedCenter]
675                 sendTwoTierAEWithRequestedKeyForNumber:@"pShf" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
676     return result;
677 }
678
679 - (BOOL)setShuffleEnabled:(BOOL)enabled
680 {
681     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[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] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
682     return YES;
683 }
684
685 - (ITMTRemotePlayerRepeatMode)repeatMode
686 {
687     FourCharCode m00f = 0;
688     int result = 0;
689     m00f = [[ITAppleEventCenter sharedCenter]
690                 sendTwoTierAEWithRequestedKeyForNumber:@"pRpt" fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd" appPSN:savedPSN];
691
692     switch (m00f)
693            {
694            case 'kRp0':
695                   result = ITMTRemotePlayerRepeatOff;
696                   break;
697            case 'kRp1':
698                   result = ITMTRemotePlayerRepeatOne;
699                   break;
700            case 'kRpA':
701                   result = ITMTRemotePlayerRepeatAll;
702                   break;
703            }
704     
705     return result;
706 }
707
708 - (BOOL)setRepeatMode:(ITMTRemotePlayerRepeatMode)repeatMode
709 {
710     char *m00f = NULL;
711     switch (repeatMode)
712            {
713            case ITMTRemotePlayerRepeatOff:
714                   m00f = "kRp0";
715                   break;
716            case ITMTRemotePlayerRepeatOne:
717                   m00f = "kRp1";
718                   break;
719            case ITMTRemotePlayerRepeatAll:
720                   m00f = "kRpA";
721                   break;
722            }
723
724     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"data:type('%s') ----:obj { form:'prop', want:type('pRpt'), seld:type('pShf'), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:'null'() } }",m00f] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
725     return YES;
726 }
727
728 - (BOOL)play
729 {
730     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
731     return YES;
732 }
733
734 - (BOOL)pause
735 {
736     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Paus" appPSN:savedPSN];
737     return YES;
738 }
739
740 - (BOOL)goToNextSong
741 {
742     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Next" appPSN:savedPSN];
743     return YES;
744 }
745
746 - (BOOL)goToPreviousSong
747 {
748     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Prev" appPSN:savedPSN];
749     return YES;
750 }
751
752 - (BOOL)forward
753 {
754     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Fast" appPSN:savedPSN];
755     return YES;
756 }
757
758 - (BOOL)rewind
759 {
760     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Rwnd" appPSN:savedPSN];
761     return YES;
762 }
763
764 - (BOOL)switchToPlaylistAtIndex:(int)index
765 {
766     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cPly'), seld:long(%lu), from:() }",index] eventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
767     return YES;
768 }
769
770 - (BOOL)switchToSongAtIndex:(int)index
771 {
772     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[NSString stringWithFormat:@"'----':obj { form:'indx', want:type('cTrk'), seld:long(%lu), from:obj { form:'prop', want:type('prop'), seld:type('pPla'), from:() } }",index] eventClass:@"hook" eventID:@"Play" appPSN:savedPSN];
773     return YES;
774 }
775
776 - (BOOL)switchToEQAtIndex:(int)index
777 {
778     // index should count from 0, but itunes counts from 1, so let's add 1.
779     [[ITAppleEventCenter sharedCenter] sendAEWithSendString:[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)] eventClass:@"core" eventID:@"setd" appPSN:savedPSN];
780     return YES;
781 }
782
783 - (ProcessSerialNumber)iTunesPSN
784 {
785     /*NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
786     ProcessSerialNumber number;
787     int i;
788     int count = [apps count];
789     
790     number.highLongOfPSN = kNoProcess;
791     
792     for (i = 0; i < count; i++)
793     {
794         NSDictionary *curApp = [apps objectAtIndex:i];
795         
796         if ([[curApp objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"])
797         {
798             number.highLongOfPSN = [[curApp objectForKey:
799                 @"NSApplicationProcessSerialNumberHigh"] intValue];
800             number.lowLongOfPSN = [[curApp objectForKey:
801                 @"NSApplicationProcessSerialNumberLow"] intValue];
802         }
803     }
804     return number;*//*
805     ProcessSerialNumber number;
806     number.highLongOfPSN = kNoProcess;
807     number.lowLongOfPSN = 0;
808     
809     while ( (GetNextProcess(&number) == noErr) ) 
810     {
811         CFStringRef name;
812         if ( (CopyProcessName(&number, &name) == noErr) )
813         {
814             if ([(NSString *)name isEqualToString:@"iTunes"])
815             {
816                 return number;
817             }
818             [(NSString *)name release];
819         }
820     }
821     return number;
822 }*/
823
824 @end