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