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.";
27 iTunesPSN = [self iTunesPSN];
28 asComponent = OpenDefaultComponent(kOSAComponentType, kAppleScriptSubtype);
30 //Register for application termination in NSWorkspace
31 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationLaunched:) name:NSWorkspaceDidLaunchApplicationNotification object:nil];
32 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationTerminated:) name:NSWorkspaceDidTerminateApplicationNotification object:nil];
34 NSLog(@"iTunes Plugin loaded");
40 iTunesPSN.highLongOfPSN = kNoProcess;
41 CloseComponent(asComponent);
43 //Unregister for application termination in NSWorkspace
44 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
49 - (void)applicationLaunched:(NSNotification *)note
51 NSDictionary *info = [note userInfo];
53 if ([[info objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) {
54 iTunesPSN.highLongOfPSN = [[info objectForKey:@"NSApplicationProcessSerialNumberHigh"] longValue];
55 iTunesPSN.lowLongOfPSN = [[info objectForKey:@"NSApplicationProcessSerialNumberLow"] longValue];
57 [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTRemoteAppDidLaunchNotification" object:nil];
61 - (void)applicationTerminated:(NSNotification *)note
63 NSDictionary *info = [note userInfo];
65 if ([[info objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"]) {
66 iTunesPSN.highLongOfPSN = kNoProcess;
67 [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTRemoteAppDidTerminateNotification" object:nil];
71 - (PlayerState)playerState
73 NSString *result = [self runScriptAndReturnResult:@"get player state"];
75 if ([result isEqualToString:@"playing"]) {
77 } else if ([result isEqualToString:@"paused"]) {
79 } else if ([result isEqualToString:@"stopped"]) {
81 } else if ([result isEqualToString:@"rewinding"]) {
83 } else if ([result isEqualToString:@"fast forwarding"]) {
90 - (NSArray *)playlists
93 int numPresets = [[self runScriptAndReturnResult:@"get number of playlists"] intValue];
94 NSMutableArray *presets = [[NSMutableArray alloc] init];
96 for (i = 0; i < numPresets; i++) {
97 [presets addObject:[self runScriptAndReturnResult:[NSString stringWithFormat:@"get name of playlist %i", i]]];
100 return [NSArray arrayWithArray:presets];
103 - (int)numberOfSongsInPlaylistAtIndex:(int)index
105 NSString *result = [self runScriptAndReturnResult:[NSString stringWithFormat:@"get number of tracks in playlist %i", index]];
106 return [result intValue];
109 - (NSString *)classOfPlaylistAtIndex:(int)index
111 //Not working yet. It returns the 4 character code instead of a name.
113 result = [[ITAppleEventCenter sharedCenter]
114 sendTwoTierAEWithRequestedKey:@"pcls"
115 fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd"
116 appPSN:[self iTunesPSN]];*/
117 NSString *result = [self runScriptAndReturnResult:[NSString stringWithFormat:@"get class of playlist %i", index]];
121 - (int)currentPlaylistIndex
124 result = [[ITAppleEventCenter sharedCenter]
125 sendTwoTierAEWithRequestedKeyForNumber:@"pidx"
126 fromObjectByKey:@"pPla" eventClass:@"core" eventID:@"getd"
127 appPSN:[self iTunesPSN]];
131 - (NSString *)songTitleAtIndex:(int)index
133 NSString *result = [self runScriptAndReturnResult:[NSString stringWithFormat:@"get name of track %i of current playlist", index]];
137 - (int)currentSongIndex
140 result = [[ITAppleEventCenter sharedCenter]
141 sendTwoTierAEWithRequestedKeyForNumber:@"pidx"
142 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
143 appPSN:[self iTunesPSN]];
147 - (NSString *)currentSongTitle
149 return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pnam"
150 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
151 appPSN:[self iTunesPSN]];
154 - (NSString *)currentSongArtist
156 return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pArt"
157 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
158 appPSN:[self iTunesPSN]];
161 - (NSString *)currentSongAlbum
163 return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pAlb"
164 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
165 appPSN:[self iTunesPSN]];
168 - (NSString *)currentSongGenre
170 return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pGen"
171 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
172 appPSN:[self iTunesPSN]];
175 - (NSString *)currentSongLength
177 return [[ITAppleEventCenter sharedCenter] sendTwoTierAEWithRequestedKey:@"pTim"
178 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
179 appPSN:[self iTunesPSN]];
182 - (NSString *)currentSongRemaining
184 long duration = [[ITAppleEventCenter sharedCenter]
185 sendTwoTierAEWithRequestedKeyForNumber:@"pDur"
186 fromObjectByKey:@"pTrk" eventClass:@"core" eventID:@"getd"
187 appPSN:[self iTunesPSN]];
188 long current = [[ITAppleEventCenter sharedCenter]
189 sendAEWithRequestedKeyForNumber:@"pPos"
190 eventClass:@"core" eventID:@"getd"
191 appPSN:[self iTunesPSN]];
193 return [[NSNumber numberWithLong:duration - current] stringValue];
196 - (NSArray *)eqPresets;
199 int numPresets = [[self runScriptAndReturnResult:@"get number of EQ presets"] intValue];
200 NSMutableArray *presets = [[NSMutableArray alloc] init];
202 for (i = 0; i < numPresets; i++) {
203 [presets addObject:[self runScriptAndReturnResult:[NSString stringWithFormat:@"get name of EQ preset %i", i]]];
206 return [NSArray arrayWithArray:presets];
209 - (int)currentEQPresetIndex
212 result = [[ITAppleEventCenter sharedCenter]
213 sendTwoTierAEWithRequestedKeyForNumber:@"pidx"
214 fromObjectByKey:@"pEQP" eventClass:@"core" eventID:@"getd"
215 appPSN:[self iTunesPSN]];
221 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Play"
222 appPSN:[self iTunesPSN]];
228 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Paus"
229 appPSN:[self iTunesPSN]];
235 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Next"
236 appPSN:[self iTunesPSN]];
240 - (BOOL)goToPreviousSong
242 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Prev"
243 appPSN:[self iTunesPSN]];
249 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Fast"
250 appPSN:[self iTunesPSN]];
256 [[ITAppleEventCenter sharedCenter] sendAEWithEventClass:@"hook" eventID:@"Rwnd"
257 appPSN:[self iTunesPSN]];
262 - (BOOL)switchToPlaylistAtIndex:(int)index
264 [self runScriptAndReturnResult:[NSString stringWithFormat:
265 @"play playlist %i", index]];
269 - (BOOL)switchToSongAtIndex:(int)index
271 [self runScriptAndReturnResult:[NSString stringWithFormat:
272 @"play track %i of current playlist", index]];
276 - (BOOL)switchToEQAtIndex:(int)index
278 [self runScriptAndReturnResult:[NSString stringWithFormat:
279 @"set current EQ preset to EQ preset %i", index]];
280 [self runScriptAndReturnResult:@"set EQ enabled to 1"];
284 - (ProcessSerialNumber)iTunesPSN
286 NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
287 ProcessSerialNumber number;
290 number.highLongOfPSN = kNoProcess;
292 for (i = 0; i < [apps count]; i++)
294 NSDictionary *curApp = [apps objectAtIndex:i];
296 if ([[curApp objectForKey:@"NSApplicationName"] isEqualToString:@"iTunes"])
298 number.highLongOfPSN = [[curApp objectForKey:@"NSApplicationProcessSerialNumberHigh"] intValue];
299 number.lowLongOfPSN = [[curApp objectForKey:@"NSApplicationProcessSerialNumberLow"] intValue];
305 - (NSString *)runScriptAndReturnResult:(NSString *)script
307 AEDesc scriptDesc, resultDesc;
312 script = [NSString stringWithFormat:@"tell application \"iTunes\"\n%@\nend tell", script];
314 AECreateDesc(typeChar, [script cString], [script cStringLength],
317 OSADoScript(asComponent, &scriptDesc, kOSANullScript, typeChar, kOSAModeCanInteract, &resultDesc);
319 length = AEGetDescDataSize(&resultDesc);
320 buffer = malloc(length);
322 AEGetDescData(&resultDesc, buffer, length);
323 AEDisposeDesc(&scriptDesc);
324 AEDisposeDesc(&resultDesc);
325 result = [NSString stringWithCString:buffer length:length];
326 if ( (! [result isEqualToString:@""]) &&
327 ([result characterAtIndex:0] == '\"') &&
328 ([result characterAtIndex:[result length] - 1] == '\"') ) {
329 result = [result substringWithRange:NSMakeRange(1, [result length] - 2)];