Ripped out polling code. GrowlTunes 1.2.1 will require iTunes 4.7 or later.
authorPeter Hosey <hg@boredzo.org>
Sat Mar 27 22:18:39 2010 -0700 (2010-03-27)
changeset 46071965ad0e7d66
parent 4606 c9988887095c
child 4608 1b90cdbf5fc4
Ripped out polling code. GrowlTunes 1.2.1 will require iTunes 4.7 or later.

Includes a couple of new strings, for the iTunes-too-old error message.
Extras/GrowlTunes/GrowlTunesController.h
Extras/GrowlTunes/GrowlTunesController.m
     1.1 --- a/Extras/GrowlTunes/GrowlTunesController.h	Tue Mar 23 04:46:07 2010 -0700
     1.2 +++ b/Extras/GrowlTunes/GrowlTunesController.h	Sat Mar 27 22:18:39 2010 -0700
     1.3 @@ -41,8 +41,6 @@
     1.4  } iTunesState;
     1.5  
     1.6  @interface GrowlTunesController : GrowlAbstractSingletonObject <GrowlApplicationBridgeDelegate> {
     1.7 -	NSTimer				*pollTimer;
     1.8 -	NSAppleScript		*pollScript;
     1.9  	NSAppleScript		*getInfoScript;
    1.10  	NSMutableArray		*plugins;
    1.11  	NSStatusItem		*statusItem;
    1.12 @@ -54,8 +52,6 @@
    1.13  	id <GrowlTunesPluginArchive> archivePlugin;
    1.14  
    1.15  	iTunesState			state;
    1.16 -	BOOL				polling;
    1.17 -	double				pollInterval;
    1.18  	int					trackID;
    1.19  	NSString			*trackURL;		//The file location of the last-known track in iTunes, @"" for none
    1.20  	NSString			*lastPostedDescription;
    1.21 @@ -67,14 +63,6 @@
    1.22  - (BOOL) iTunesIsRunning;
    1.23  - (BOOL) quitiTunes;
    1.24  
    1.25 -- (void) setPolling:(BOOL)flag;
    1.26 -
    1.27 -#pragma mark Poll timer
    1.28 -
    1.29 -- (void) poll:(NSTimer *)timer;
    1.30 -- (void) startTimer;
    1.31 -- (void) stopTimer;
    1.32 -
    1.33  #pragma mark Status item
    1.34  
    1.35  - (void) createStatusItem;
     2.1 --- a/Extras/GrowlTunes/GrowlTunesController.m	Tue Mar 23 04:46:07 2010 -0700
     2.2 +++ b/Extras/GrowlTunes/GrowlTunesController.m	Sat Mar 27 22:18:39 2010 -0700
     2.3 @@ -57,13 +57,16 @@
     2.4  #define ITUNES_APP_NAME         @"iTunes.app"
     2.5  #define ITUNES_BUNDLE_ID        @"com.apple.itunes"
     2.6  
     2.7 -#define POLL_INTERVAL_KEY       @"Poll interval"
     2.8  #define NO_MENU_KEY             @"GrowlTunesWithoutMenu"
     2.9  #define RECENT_TRACK_COUNT_KEY  @"Recent Tracks Count"
    2.10  
    2.11 -#define DEFAULT_POLL_INTERVAL	    2
    2.12  #define DEFAULT_RECENT_TRACKS_LIMIT 20U
    2.13  
    2.14 +#define GROWLTUNES_ERROR_DOMAIN @"GrowlTunesErrorDomain"
    2.15 +enum {
    2.16 +	GrowlTunesError_iTunesTooOld = 1,
    2.17 +};
    2.18 +
    2.19  //status item menu item tags.
    2.20  enum {
    2.21  	ratingTag = -11,
    2.22 @@ -71,7 +74,6 @@
    2.23  	quitGrowlTunesTag,
    2.24  	launchQuitiTunesTag,
    2.25  	quitBothTag,
    2.26 -	togglePollingTag,
    2.27  };
    2.28  
    2.29  @implementation GrowlTunesController
    2.30 @@ -94,7 +96,6 @@
    2.31  
    2.32  	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    2.33  	NSDictionary *defaultDefaults = [[NSDictionary alloc] initWithObjectsAndKeys:
    2.34 -		[NSNumber numberWithDouble:DEFAULT_POLL_INTERVAL], POLL_INTERVAL_KEY,
    2.35  		[NSNumber numberWithInt:20],                       RECENT_TRACK_COUNT_KEY,
    2.36  		nil];
    2.37  	[defaults registerDefaults:defaultDefaults];
    2.38 @@ -118,33 +119,21 @@
    2.39  	getInfoScript = [self appleScriptNamed:@"jackItunesArtwork"];
    2.40  
    2.41  	NSString *itunesPath = [[NSWorkspace sharedWorkspace] fullPathForApplication:ITUNES_APP_NAME];
    2.42 -	if ([[[NSBundle bundleWithPath:itunesPath] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] floatValue] >= 4.7f)
    2.43 -		[self setPolling:NO];
    2.44 -	else
    2.45 -		[self setPolling:YES];
    2.46 -
    2.47 -	if (polling) {
    2.48 -		pollScript   = [self appleScriptNamed:@"jackItunesInfo"];
    2.49 -		pollInterval = [[NSUserDefaults standardUserDefaults] floatForKey:POLL_INTERVAL_KEY];
    2.50 -
    2.51 -		if ([self iTunesIsRunning]) [self startTimer];
    2.52 -
    2.53 -		NSNotificationCenter *workspaceCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
    2.54 -		[workspaceCenter addObserver:self
    2.55 -							selector:@selector(handleAppLaunch:)
    2.56 -								name:NSWorkspaceDidLaunchApplicationNotification
    2.57 -							  object:nil];
    2.58 -
    2.59 -		[workspaceCenter addObserver:self
    2.60 -							selector:@selector(handleAppQuit:)
    2.61 -								name:NSWorkspaceDidTerminateApplicationNotification
    2.62 -							  object:nil];
    2.63 -	} else {
    2.64 -		[[NSDistributedNotificationCenter defaultCenter] addObserver:self
    2.65 -															selector:@selector(songChanged:)
    2.66 -																name:@"com.apple.iTunes.playerInfo"
    2.67 -															  object:nil];
    2.68 -	}
    2.69 +	if ([[[NSBundle bundleWithPath:itunesPath] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] floatValue] < 4.7f) {
    2.70 +		NSError *error = [NSError errorWithDomain:GROWLTUNES_ERROR_DOMAIN code:GrowlTunesError_iTunesTooOld userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
    2.71 +			NSLocalizedString(@"This version of iTunes is too old.", /*comment*/ nil), NSLocalizedDescriptionKey,
    2.72 +			NSLocalizedString(@"Please update to version 4.7 or later of iTunes.", /*comment*/ nil), NSLocalizedRecoverySuggestionErrorKey,
    2.73 +			nil]];
    2.74 +		[NSApp presentError:error];
    2.75 +
    2.76 +		[NSApp terminate:nil];
    2.77 +	}
    2.78 +
    2.79 +	[[NSDistributedNotificationCenter defaultCenter] addObserver:self
    2.80 +														selector:@selector(songChanged:)
    2.81 +															name:@"com.apple.iTunes.playerInfo"
    2.82 +														  object:nil];
    2.83 +
    2.84  	if (![[NSUserDefaults standardUserDefaults] boolForKey:NO_MENU_KEY])
    2.85  		[self createStatusItem];
    2.86  }
    2.87 @@ -153,10 +142,8 @@
    2.88  #pragma unused(notification)
    2.89  	[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
    2.90  	[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
    2.91 -	[self stopTimer];
    2.92  	[self tearDownStatusItem];
    2.93  
    2.94 -	[pollScript    release]; 
    2.95  	[getInfoScript release];
    2.96  	[recentTracks  release];
    2.97  
    2.98 @@ -198,10 +185,6 @@
    2.99  	return APP_NAME;
   2.100  }
   2.101  
   2.102 -- (void) setPolling:(BOOL)flag {
   2.103 -	polling = flag;
   2.104 -}
   2.105 -
   2.106  #pragma mark -
   2.107  
   2.108  - (NSString *) starsForRating:(NSNumber *)aRating withStarCharacter:(unichar)star {
   2.109 @@ -530,162 +513,11 @@
   2.110  	}
   2.111  }
   2.112  
   2.113 -#pragma mark Poll timer
   2.114 -
   2.115 -- (void) poll:(NSTimer *)timer {
   2.116 -#pragma unused(timer)
   2.117 -	NSDictionary			*error = nil;
   2.118 -	NSAppleEventDescriptor	*theDescriptor = [pollScript executeAndReturnError:&error];
   2.119 -	NSAppleEventDescriptor  *curDescriptor;
   2.120 -	NSString				*playerState;
   2.121 -	iTunesState				newState = itUNKNOWN;
   2.122 -	int						newTrackID = -1;
   2.123 -
   2.124 -	curDescriptor = [theDescriptor descriptorAtIndex:1L];
   2.125 -	playerState = [curDescriptor stringValue];
   2.126 -
   2.127 -	if ([playerState isEqualToString:@"paused"]) {
   2.128 -		newState = itPAUSED;
   2.129 -	} else if ([playerState isEqualToString:@"stopped"]) {
   2.130 -		newState = itSTOPPED;
   2.131 -		trackRating = -1;
   2.132 -		[noteDict release];
   2.133 -		noteDict = nil;
   2.134 -	} else {
   2.135 -		newState = itPLAYING;
   2.136 -		newTrackID = [curDescriptor int32Value];
   2.137 -	}
   2.138 -
   2.139 -	if (state == itUNKNOWN) {
   2.140 -		state = newState;
   2.141 -		trackID = newTrackID;
   2.142 -		return;
   2.143 -	}
   2.144 -
   2.145 -	if (newTrackID) {
   2.146 -		NSString		*track = nil;
   2.147 -		NSString		*length = nil;
   2.148 -		NSString		*artist = nil;
   2.149 -		NSString		*album = nil;
   2.150 -		NSString		*composer = nil;
   2.151 -		BOOL			 compilation = NO;
   2.152 -		NSString		*genre = nil;
   2.153 -		NSNumber		*rating = nil;
   2.154 -		NSString		*ratingString = nil;
   2.155 -		NSImage			*artwork = nil;
   2.156 -
   2.157 -		curDescriptor = [theDescriptor descriptorAtIndex:10L];
   2.158 -		playlistName = [curDescriptor stringValue];
   2.159 -
   2.160 -		if ((curDescriptor = [theDescriptor descriptorAtIndex:2L]))
   2.161 -			track = [curDescriptor stringValue];
   2.162 -
   2.163 -		if ((curDescriptor = [theDescriptor descriptorAtIndex:3L]))
   2.164 -			length = [curDescriptor stringValue];
   2.165 -
   2.166 -		if ((curDescriptor = [theDescriptor descriptorAtIndex:4L]))
   2.167 -			artist = [curDescriptor stringValue];
   2.168 -
   2.169 -		if ((curDescriptor = [theDescriptor descriptorAtIndex:5L]))
   2.170 -			album = [curDescriptor stringValue];
   2.171 -
   2.172 -		if ((curDescriptor = [theDescriptor descriptorAtIndex:6L]))
   2.173 -			composer = [curDescriptor stringValue];
   2.174 -
   2.175 -		if ((curDescriptor = [theDescriptor descriptorAtIndex:7L]))
   2.176 -			compilation = (BOOL)[curDescriptor booleanValue];
   2.177 -
   2.178 -		if ((curDescriptor = [theDescriptor descriptorAtIndex:8L]))
   2.179 -			genre = [curDescriptor stringValue];
   2.180 -
   2.181 -		if ((curDescriptor = [theDescriptor descriptorAtIndex:9L])) {
   2.182 -			trackRating = [[curDescriptor stringValue] intValue];
   2.183 -			rating = [NSNumber numberWithInt:trackRating < 0 ? 0 : trackRating];
   2.184 -			ratingString = [self starsForRating:rating];
   2.185 -		}
   2.186 -
   2.187 -		curDescriptor = [theDescriptor descriptorAtIndex:10L];
   2.188 -		const OSType type = [curDescriptor typeCodeValue];
   2.189 -
   2.190 -		if (type != 'null') {
   2.191 -			artwork = [[[NSImage alloc] initWithData:[curDescriptor data]] autorelease];
   2.192 -		} else {
   2.193 -			NSEnumerator *pluginEnum = [plugins objectEnumerator];
   2.194 -			id <GrowlTunesPlugin> plugin;
   2.195 -			while (!artwork && (plugin = [pluginEnum nextObject])) {
   2.196 -				artwork = [plugin artworkForTitle:track
   2.197 -										 byArtist:artist
   2.198 -										  onAlbum:album
   2.199 -									   composedBy:composer
   2.200 -									isCompilation:compilation];
   2.201 -				if (artwork && [plugin usesNetwork])
   2.202 -					[archivePlugin archiveImage:artwork	track:track artist:artist album:album composer:composer compilation:compilation];
   2.203 -			}
   2.204 -		}
   2.205 -
   2.206 -		if (!artwork) {
   2.207 -			if (!error) {
   2.208 -				NSLog(@"Error getting artwork: %@", [error objectForKey:NSAppleScriptErrorMessage]);
   2.209 -				if ([plugins count]) NSLog(@"No plug-ins found anything either, or you wouldn't have this message.");
   2.210 -			}
   2.211 -
   2.212 -			// Use the iTunes icon instead
   2.213 -			artwork = [[NSWorkspace sharedWorkspace] iconForApplication:ITUNES_APP_NAME];
   2.214 -			[artwork setSize:NSMakeSize(128.0f, 128.0f)];
   2.215 -		}
   2.216 -
   2.217 -		NSString *description = [[NSString alloc] initWithFormat:@"%@ - %@\n%@ (Composed by %@)\n%@\n%@", length, ratingString, artist, composer, album, genre];
   2.218 -		[noteDict release];
   2.219 -		noteDict = [[NSDictionary alloc] initWithObjectsAndKeys:
   2.220 -			(state == itPLAYING ? ITUNES_TRACK_CHANGED : ITUNES_PLAYING), GROWL_NOTIFICATION_NAME,
   2.221 -			APP_NAME,                     GROWL_APP_NAME,
   2.222 -			track,                        GROWL_NOTIFICATION_TITLE,
   2.223 -			description,                  GROWL_NOTIFICATION_DESCRIPTION,
   2.224 -			APP_NAME,                     GROWL_NOTIFICATION_IDENTIFIER,
   2.225 -			[artwork TIFFRepresentation], GROWL_NOTIFICATION_ICON,
   2.226 -			nil];
   2.227 -		[description release];
   2.228 -
   2.229 -		if (trackID != newTrackID) { // this is different from previous note
   2.230 -			// Tell growl
   2.231 -			[GrowlApplicationBridge notifyWithDictionary:noteDict];
   2.232 -
   2.233 -			// Recent Tracks
   2.234 -			[self addTuneToRecentTracks:track fromPlaylist:playlistName];
   2.235 -		}
   2.236 -
   2.237 -		// set up us some state for next time
   2.238 -		state = newState;
   2.239 -		trackID = newTrackID;
   2.240 -	}
   2.241 -}
   2.242 -
   2.243  - (void) showCurrentTrack {
   2.244  	if (noteDict)
   2.245  		[GrowlApplicationBridge notifyWithDictionary:noteDict];
   2.246  }
   2.247  
   2.248 -- (void) startTimer {
   2.249 -	if (!pollTimer) {
   2.250 -		pollTimer = [[NSTimer scheduledTimerWithTimeInterval:pollInterval
   2.251 -													  target:self
   2.252 -													selector:@selector(poll:)
   2.253 -													userInfo:nil
   2.254 -													 repeats:YES] retain];
   2.255 -		NSLog(@"%@", @"Polling started - upgrade to iTunes 4.7 or later already, would you?!");
   2.256 -		[self poll:nil];
   2.257 -	}
   2.258 -}
   2.259 -
   2.260 -- (void) stopTimer {
   2.261 -	if (pollTimer){
   2.262 -		[pollTimer invalidate];
   2.263 -		[pollTimer release];
   2.264 -		pollTimer = nil;
   2.265 -		NSLog(@"%@", @"Polling stopped");
   2.266 -	}
   2.267 -}
   2.268 -
   2.269  #pragma mark Status item
   2.270  
   2.271  - (void) createStatusItem {
   2.272 @@ -744,29 +576,11 @@
   2.273  		[item setTarget:self];
   2.274  		[item setTag:quitBothTag];
   2.275  		[item setToolTip:NSLocalizedString(@"Quits both iTunes and GrowlTunes", /*comment*/ nil)];
   2.276 -
   2.277 -		if (polling) {
   2.278 -			item = [NSMenuItem separatorItem];
   2.279 -			[menu addItem:item];
   2.280 -
   2.281 -			item = [menu addItemWithTitle:@"Toggle Polling" action:@selector(togglePolling:) keyEquivalent:empty];
   2.282 -			[item setTarget:self];
   2.283 -			[item setTag:togglePollingTag];
   2.284 -			[item setToolTip:NSLocalizedString(@"Turns on or off GrowlTunes' periodic asking of iTunes for track information.", "Toggle polling tooltip")];
   2.285 -		}
   2.286  	}
   2.287  
   2.288  	return [menu autorelease];
   2.289  }
   2.290  
   2.291 -- (IBAction) togglePolling:(id)sender {
   2.292 -#pragma unused(sender)
   2.293 -	if (pollTimer)
   2.294 -		[self stopTimer];
   2.295 -	else
   2.296 -		[self startTimer];
   2.297 -}
   2.298 -
   2.299  - (NSMenu *) buildiTunesSubmenu {
   2.300  	NSMenuItem * item;
   2.301  	if (!iTunesSubMenu)
   2.302 @@ -859,15 +673,6 @@
   2.303  			retVal = [self iTunesIsRunning];
   2.304  			break;
   2.305  
   2.306 -		case togglePollingTag:
   2.307 -			if (pollTimer) {
   2.308 -				[item setTitle:NSLocalizedString(@"Stop Polling", @"")];
   2.309 -				[item setToolTip:NSLocalizedString(@"Stops GrowlTunes from asking iTunes for track information. You will then no longer receive Growl notifications from GrowlTunes.", "Tooltip for 'stop polling'")];
   2.310 -			} else {
   2.311 -				[item setTitle:NSLocalizedString(@"Start Polling", @"")];
   2.312 -				[item setToolTip:NSLocalizedString(@"Begins asking iTunes for track information. You will then start receiving Growl notifications from GrowlTunes.", "Tooltip for 'start polling'")];
   2.313 -			}
   2.314 -
   2.315  		case quitGrowlTunesTag:
   2.316  		case onlineHelpTag:
   2.317  			break;
   2.318 @@ -938,10 +743,6 @@
   2.319  	NSDictionary *iTunes = [[NSWorkspace sharedWorkspace] launchedApplicationWithIdentifier:ITUNES_BUNDLE_ID];
   2.320  	BOOL success = (iTunes != nil);
   2.321  	if (success) {
   2.322 -		//first disarm the timer. we don't want to launch iTunes right after we quit it if the timer fires.
   2.323 -		[self stopTimer];
   2.324 -
   2.325 -		//now quit iTunes.
   2.326  		NSAppleEventDescriptor *target = [[NSAppleEventDescriptor alloc] initWithDescriptorType:typeApplicationBundleID
   2.327  																						   data:[ITUNES_BUNDLE_ID dataUsingEncoding:NSUTF8StringEncoding]];
   2.328  		NSAppleEventDescriptor *event = [[NSAppleEventDescriptor alloc] initWithEventClass:kCoreEventClass
   2.329 @@ -1057,16 +858,6 @@
   2.330  	[jumpScript release];
   2.331  }
   2.332  
   2.333 -- (void) handleAppLaunch:(NSNotification *)notification {
   2.334 -	if ([ITUNES_BUNDLE_ID caseInsensitiveCompare:[[notification userInfo] objectForKey:@"NSApplicationBundleIdentifier"]] == NSOrderedSame)
   2.335 -		[self startTimer];
   2.336 -}
   2.337 -
   2.338 -- (void) handleAppQuit:(NSNotification *)notification {
   2.339 -	if ([ITUNES_BUNDLE_ID caseInsensitiveCompare:[[notification userInfo] objectForKey:@"NSApplicationBundleIdentifier"]] == NSOrderedSame)
   2.340 -		[self stopTimer];
   2.341 -}
   2.342 -
   2.343  #pragma mark Plug-ins
   2.344  
   2.345  // This function is used to sort plugins, trying first the local ones, and then the network ones