1 #import "iTunesRemote.h"
3 @implementation iTunesRemote
7 return [[[iTunesRemote alloc] init] autorelease];
12 return @"iTunes Plug-in";
15 - (NSString *)information;
17 return @"Default MenuTunes plugin to control iTunes. Written by iThink Software.";
27 iTunesPSN = [self iTunesPSN];
29 //We won't need this once we're pure AEs
30 asComponent = OpenDefaultComponent(kOSAComponentType, kAppleScriptSubtype);
32 //Register for application termination in NSWorkspace
33 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationLaunched:) name:NSWorkspaceDidLaunchApplicationNotification object:nil];
34 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationTerminated:) name:NSWorkspaceDidTerminateApplicationNotification object:nil];
41 iTunesPSN.highLongOfPSN = kNoProcess;
43 //We won't need this once we're pure AEs
44 CloseComponent(asComponent);
46 //Unregister for application termination in NSWorkspace
47 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
54 NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
57 for (i = 0; i < [apps count]; i++) {
58 if ([[[apps objectAtIndex:i] objectForKey:@"NSApplicationName"]
59 isEqualToString:@"iTunes"]) {
66 - (PlayerState)playerState
68 NSString *result = [self runScriptAndReturnResult:@"get player state"];
70 if ([result isEqualToString:@"playing"]) {
72 } else if ([result isEqualToString:@"paused"]) {
74 } else if ([result isEqualToString:@"stopped"]) {
76 } else if ([result isEqualToString:@"rewinding"]) {
78 } else if ([result isEqualToString:@"fast forwarding"]) {
85 - (NSArray *)playlists
88 int numPresets = [[self runScriptAndReturnResult:@"get number of playlists"] intValue];
89 NSMutableArray *presets = [[NSMutableArray alloc] init];
90 for (i = 1; i <= numPresets; i++) {
91 [presets addObject:[self runScriptAndReturnResult:[NSString stringWithFormat:@"get name of playlist %i", i]]];
94 return [NSArray arrayWithArray:presets];
97 - (int)numberOfSongsInPlaylistAtIndex:(int)index
99 NSString *result = [self runScriptAndReturnResult:[NSString stringWithFormat:@"get number of tracks in playlist %i", index]];
100 return [result intValue];
103 - (NSString *)classOfPlaylistAtIndex:(int)index
105 //Not working yet. It returns the 4 character code instead of a name.
107 result = [[ITAppleEventCenter sharedCenter]
108 sendTwoTierAEWithRequestedKey:@"pcls"
109 fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd"
110 appPSN:[self iTunesPSN]];*/
111 NSString *result = [self runScriptAndReturnResult:[NSString stringWithFormat:@"get class of playlist %i", index]];
115 - (int)currentPlaylistIndex
118 result = [[ITAppleEventCenter sharedCenter]
119 sendTwoTierAEWithRequestedKeyForNumber:@"pidx"
120 fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd"
121 appPSN:[self iTunesPSN]];
125 - (NSString *)songTitleAtIndex:(int)index
127 NSString *result = [self runScriptAndReturnResult:[NSString stringWithFormat:@"get name of track %i of current playlist", index]];
131 - (int)currentSongIndex
134 result = [[ITAppleEventCenter sharedCenter]
135 sendTwoTierAEWithRequestedKeyForNumber:@"pidx"
136 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
137 appPSN:[self iTunesPSN]];
141 - (NSString *)currentSongTitle
143 return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pnam"
144 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
145 appPSN:[self iTunesPSN]];
148 - (NSString *)currentSongArtist
150 return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pArt"
151 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
152 appPSN:[self iTunesPSN]];
155 - (NSString *)currentSongAlbum
157 return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pAlb"
158 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
159 appPSN:[self iTunesPSN]];
162 - (NSString *)currentSongGenre
164 return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pGen"
165 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
166 appPSN:[self iTunesPSN]];
169 - (NSString *)currentSongLength
171 return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pTim"
172 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
173 appPSN:[self iTunesPSN]];
176 - (NSString *)currentSongRemaining
178 long duration = [[ITAppleEventCenter sharedCenter]
179 sendTwoTierAEWithRequestedKeyForNumber:@"pDur"
180 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
181 appPSN:[self iTunesPSN]];
182 long current = [[ITAppleEventCenter sharedCenter]
183 sendAEWithRequestedKeyForNumber:@"pPos"
184 eventClass:@"core" eventID:@"getd"
185 appPSN:[self iTunesPSN]];
187 return [[NSNumber numberWithLong:duration - current] stringValue];
190 - (NSArray *)eqPresets;
193 int numPresets = [[self runScriptAndReturnResult:@"get number of EQ presets"] intValue];
194 NSMutableArray *presets = [[NSMutableArray alloc] init];
196 for (i = 1; i <= numPresets; i++) {
197 [presets addObject:[self runScriptAndReturnResult:[NSString stringWithFormat:@"get name of EQ preset %i", i]]];
200 return [NSArray arrayWithArray:presets];
203 - (int)currentEQPresetIndex
206 result = [[ITAppleEventCenter sharedCenter]
207 sendTwoTierAEWithRequestedKeyForNumber:@"pidx"
208 fromObjectByKey:@"pEQP" eventClass:@"core" eventID:@"getd"
209 appPSN:[self iTunesPSN]];
215 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Play"
216 appPSN:[self iTunesPSN]];
222 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Paus"
223 appPSN:[self iTunesPSN]];
229 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Next"
230 appPSN:[self iTunesPSN]];
234 - (BOOL)goToPreviousSong
236 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Prev"
237 appPSN:[self iTunesPSN]];
243 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Fast"
244 appPSN:[self iTunesPSN]];
250 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Rwnd"
251 appPSN:[self iTunesPSN]];
256 - (BOOL)switchToPlaylistAtIndex:(int)index
258 [self runScriptAndReturnResult:[NSString stringWithFormat:
259 @"play playlist %i", index]];
263 - (BOOL)switchToSongAtIndex:(int)index
265 [self runScriptAndReturnResult:[NSString stringWithFormat:
266 @"play track %i of current playlist", index]];
270 - (BOOL)switchToEQAtIndex:(int)index
272 [self runScriptAndReturnResult:[NSString stringWithFormat:
273 @"set current EQ preset to EQ preset %i", index]];
274 [self runScriptAndReturnResult:@"set EQ enabled to 1"];
278 - (ProcessSerialNumber)iTunesPSN
280 NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
281 ProcessSerialNumber number;
284 number.highLongOfPSN = kNoProcess;
286 for (i = 0; i < [apps count]; i++)
288 NSDictionary *curApp = [apps objectAtIndex:i];
290 if ([[curApp objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"])
292 number.highLongOfPSN = [[curApp objectForKey:@"NSApplicationProcessSerialNumberHigh"] intValue];
293 number.lowLongOfPSN = [[curApp objectForKey:@"NSApplicationProcessSerialNumberLow"] intValue];
299 - (void)applicationLaunched:(NSNotification *)note
301 NSDictionary *info = [note userInfo];
303 if ([[info objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) {
304 iTunesPSN.highLongOfPSN = [[info objectForKey:@"NSApplicationProcessSerialNumberHigh"] longValue];
305 iTunesPSN.lowLongOfPSN = [[info objectForKey:@"NSApplicationProcessSerialNumberLow"] longValue];
307 [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTRemoteAppDidLaunchNotification" object:nil];
311 - (void)applicationTerminated:(NSNotification *)note
313 NSDictionary *info = [note userInfo];
315 if ([[info objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) {
316 iTunesPSN.highLongOfPSN = kNoProcess;
317 [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTRemoteAppDidTerminateNotification" object:nil];
321 //This is just temporary
322 - (NSString *)runScriptAndReturnResult:(NSString *)script
324 AEDesc scriptDesc, resultDesc;
329 script = [NSString stringWithFormat:@"tell application \"iTunes\"\n%@\nend tell", script];
331 AECreateDesc(typeChar, [script cString], [script cStringLength],
334 OSADoScript(asComponent, &scriptDesc, kOSANullScript, typeChar, kOSAModeCanInteract, &resultDesc);
336 length = AEGetDescDataSize(&resultDesc);
337 buffer = malloc(length);
339 AEGetDescData(&resultDesc, buffer, length);
340 AEDisposeDesc(&scriptDesc);
341 AEDisposeDesc(&resultDesc);
342 result = [NSString stringWithCString:buffer length:length];
343 if ( (! [result isEqualToString:@""]) &&
344 ([result characterAtIndex:0] == '\"') &&
345 ([result characterAtIndex:[result length] - 1] == '\"') ) {
346 result = [result substringWithRange:NSMakeRange(1, [result length] - 2)];