Finished the plugin using my runScriptAndReturnResult method.
[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 - (NSString *)title
11 {
12     return @"iTunes Plug-in";
13 }
14
15 - (NSString *)information;
16 {
17     return @"Default MenuTunes plugin to control iTunes.";
18 }
19
20 - (NSImage *)icon
21 {
22     return nil;
23 }
24
25 - (BOOL)begin
26 {
27     iTunesPSN = [self iTunesPSN];
28     asComponent = OpenDefaultComponent(kOSAComponentType, kAppleScriptSubtype);
29     
30     //Register for application termination in NSWorkspace
31     
32     NSLog(@"iTunes Plugin loaded");
33     return YES;
34 }
35
36 - (BOOL)halt
37 {
38     iTunesPSN.highLongOfPSN = kNoProcess;
39     CloseComponent(asComponent);
40     
41     //Unregister for application termination in NSWorkspace
42     return YES;
43 }
44
45 - (int)numberOfPlaylists
46 {
47     NSString *result = [self runScriptAndReturnResult:@"get number of playlists"];
48     return [result intValue];
49 }
50
51 - (int)numberOfSongsInPlaylistAtIndex:(int)index
52 {
53     NSString *result = [self runScriptAndReturnResult:[NSString stringWithFormat:@"get number of tracks in playlist %i", index]];
54     return [result intValue];
55 }
56
57 - (NSString *)classOfPlaylistAtIndex:(int)index
58 {
59     //Not working yet. It returns the 4 character code instead of a name.
60     /*NSString *result;
61     result = [[ITAppleEventCenter sharedCenter]
62                 sendTwoTierAEWithRequestedKey:@"pcls"
63                 fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd"
64                 appPSN:[self iTunesPSN]];*/
65     NSString *result = [self runScriptAndReturnResult:[NSString stringWithFormat:@"get class of playlist %i", index]];
66     return result;
67 }
68
69 - (int)currentPlaylistIndex
70 {
71     int result;
72     result = [[ITAppleEventCenter sharedCenter]
73                 sendTwoTierAEWithRequestedKeyForNumber:@"pidx"
74                 fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd"
75                 appPSN:[self iTunesPSN]];
76     return result;
77 }
78
79 - (NSString *)songTitleAtIndex:(int)index
80 {
81     NSString *result = [self runScriptAndReturnResult:[NSString stringWithFormat:@"return name of track %i", index]];
82     return result;
83 }
84
85 - (int)currentSongIndex
86 {
87     int result;
88     result = [[ITAppleEventCenter sharedCenter]
89                 sendTwoTierAEWithRequestedKeyForNumber:@"pidx"
90                 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
91                 appPSN:[self iTunesPSN]];
92     return result;
93 }
94
95 - (NSString *)currentSongTitle
96 {
97     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pnam"
98                 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
99                 appPSN:[self iTunesPSN]];
100 }
101
102 - (NSString *)currentSongArtist
103 {
104     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pArt"
105                 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
106                 appPSN:[self iTunesPSN]];
107 }
108
109 - (NSString *)currentSongAlbum
110 {
111     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pAlb"
112                 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
113                 appPSN:[self iTunesPSN]];
114 }
115
116 - (NSString *)currentSongGenre
117 {
118     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pGen"
119                 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
120                 appPSN:[self iTunesPSN]];
121 }
122
123 - (NSString *)currentSongLength
124 {
125     return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pDur"
126                 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
127                 appPSN:[self iTunesPSN]];
128 }
129
130 - (NSString *)currentSongRemaining
131 {
132     long duration = [[ITAppleEventCenter sharedCenter]
133                         sendTwoTierAEWithRequestedKeyForNumber:@"pDur"
134                         fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
135                         appPSN:[self iTunesPSN]];
136     long current = [[ITAppleEventCenter sharedCenter]
137                         sendAEWithRequestedKeyForNumber:@"pPos"
138                         eventClass:@"core" eventID:@"getd"
139                         appPSN:[self iTunesPSN]];
140     
141     return [[NSNumber numberWithLong:duration - current] stringValue];
142 }
143
144 - (NSArray *)eqPresets;
145 {
146     int i;
147     int numPresets = [[self runScriptAndReturnResult:@"get number of EQ presets"] intValue];
148     NSMutableArray *presets = [[NSMutableArray alloc] init];
149     
150     for (i = 0; i < numPresets; i++) {
151         [presets addObject:[self runScriptAndReturnResult:[NSString stringWithFormat:@"get name of EQ preset %i", i]]];
152     }
153     
154     return [NSArray arrayWithArray:presets];
155 }
156
157 - (BOOL)play
158 {
159     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Play"
160             appPSN:[self iTunesPSN]];
161     return YES;
162 }
163
164 - (BOOL)pause
165 {
166     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Paus"
167             appPSN:[self iTunesPSN]];
168     return YES;
169 }
170
171 - (BOOL)goToNextSong
172 {
173     NSLog(@"%@", [self classOfPlaylistAtIndex:3]);
174     //[[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Next"
175     //        appPSN:[self iTunesPSN]];
176     return YES;
177 }
178
179 - (BOOL)goToPreviousSong
180 {
181     [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Prev"
182             appPSN:[self iTunesPSN]];
183     return YES;
184 }
185
186 - (BOOL)switchToPlaylistAtIndex:(int)index
187 {
188     [self runScriptAndReturnResult:[NSString stringWithFormat:
189         @"set current playlist to playlist %i", index]];
190     return NO;
191 }
192
193 - (BOOL)switchToSongAtIndex:(int)index
194 {
195     [self runScriptAndReturnResult:[NSString stringWithFormat:
196         @"play track %i of current playlist", index]];
197     return NO;
198 }
199
200 - (BOOL)switchToEQAtIndex:(int)index
201 {
202     [self runScriptAndReturnResult:[NSString stringWithFormat:
203         @"set current EQ preset to EQ preset %i", index]];
204     return NO;
205 }
206
207 - (ProcessSerialNumber)iTunesPSN
208 {
209     NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
210     ProcessSerialNumber number;
211     int i;
212     
213     number.highLongOfPSN = kNoProcess;
214     
215     for (i = 0; i < [apps count]; i++)
216     {
217         NSDictionary *curApp = [apps objectAtIndex:i];
218         
219         if ([[curApp objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"])
220         {
221             number.highLongOfPSN = [[curApp objectForKey:@"NSApplicationProcessSerialNumberHigh"] intValue];
222             number.lowLongOfPSN = [[curApp objectForKey:@"NSApplicationProcessSerialNumberLow"] intValue];
223         }
224     }
225     return number;
226 }
227
228 - (NSString *)runScriptAndReturnResult:(NSString *)script
229 {
230     AEDesc scriptDesc, resultDesc;
231     Size length;
232     NSString *result;
233     Ptr buffer;
234     
235     script = [NSString stringWithFormat:@"tell application \"iTunes\"\n%@\nend tell", script];
236     
237     AECreateDesc(typeChar, [script cString], [script cStringLength], 
238 &scriptDesc);
239     
240     OSADoScript(asComponent, &scriptDesc, kOSANullScript, typeChar, kOSAModeCanInteract, &resultDesc);
241     
242     length = AEGetDescDataSize(&resultDesc);
243     buffer = malloc(length);
244     
245     AEGetDescData(&resultDesc, buffer, length);
246     AEDisposeDesc(&scriptDesc);
247     AEDisposeDesc(&resultDesc);
248     result = [NSString stringWithCString:buffer length:length];
249     if ( (! [result isEqualToString:@""])      &&
250          ([result characterAtIndex:0] == '\"') &&
251          ([result characterAtIndex:[result length] - 1] == '\"') ) {
252         result = [result substringWithRange:NSMakeRange(1, [result length] - 2)];
253     }
254     free(buffer);
255     buffer = nil;
256     return result;
257 }
258
259 @end