One of the challenges while designing Automatic was the variety (and unpredictability) that exists in feeds. Although their structure is rigid, whether it’s RSS 1.0 or 2.0, or Atom, there is no “minimum set” of tags that must be included – meaning, there can be very little to no assumptions about the content. For Automatic, the decision was made to use the date tag to drive the matching and filtering engine. While it worked quite well, it eventually became apparent that it didn’t work when a feed “backdated” items (this usually occurs when a site allows users to create feeds “on-demand” by adding items, and an item that was added later might actually have an earlier date). It also didn’t work with feeds that have no date tag, which admittedly, are a small minority.

So, in order to support these 2 scenarios, the engine in 2.1 has been redesigned to be largely date-agnostic. The result is better support for feeds that backdate, and of course, support for feeds that have no dates.

For some subscriptions, depending on the rules set up and the previous matches, you may notice a one-time download of old items. These items were not previously downloaded by Automatic, but were ignored by the old engine. Going forward, the behavior should be the same.

Posted on Friday, September 10th, 14:59. Filed under: Automatic, Features, Mac OS X

So far, the most frequent feature request for Automatic 2 has been the ability to customize the TV Show subscriptions in some way (alternate feeds, download folders, etc). The presets have been so popular that many previous users of Automatic used them to replace their own subscriptions, but then realized they wanted to tweak them.

In all honesty, a lazy solution was easy: the flip of a switch in the code could allow any TV subscription to be edited in the Custom interface. But that solution didn’t really address the question: “Why did users so strongly prefer the presets, even over their own, already configured Custom subscriptions?”.

Apparently, the answer lies in the TV data. Every preset has information attached about the show, such as the banner and episode list, and is presented in various areas. So in 2.1, it will be possible to attach show data to Custom subscriptions as well. Not only for shows that Automatic already knows about, but for any show. Also, episode data will be presented in the Subscription pane as well: you’ll be able to toggle between the subscription history or the episode list.

In light of the improvements to presenting show data with Custom subscriptions, converting a TV Show subscription to a Custom one now makes sense. Presenting a special interface for customizing TV Show subscriptions would be a bad idea, considering there is already a very powerful and robust rule creation interface in place. So in 2.1 you will have the ability to convert a TV Show subscription and tweak it to your heart’s content. The only difference between a TV Show subscription and a Custom one with show data attached will be the section they appear in (TV Shows vs. Custom).

This solution covers all the bases: it leaves the TV Show interface intact, allows users to customize TV Show subscriptions without losing the show data, and even enables subscriptions with show data that was not previously available in Automatic.

Posted on Thursday, August 19th, 03:30. Filed under: Automatic, Features, Mac OS X

While System Preferences.app generally makes it very easy for users to install and update prefPanes, it has some idiosyncrasies. Foremost is the fact that when it comes to comparing two prefPanes, apparently only the names are compared: make a copy of an already installed prefPane, rename it and double-click; you’ll be offered to install it, rather than replace the existing one.

The second weirdness is a bit more complex, and can present problems when replacing a prefPane with one that is significantly different: on the one hand there is the installed prefPane, and on the other the new one, with the same name but a different bundle identifier. As mentioned above, System Preferences.app considers these two to be the same, based on their shared name.

When installing the new prefPane, System Preferences.app presumably calls unload on the old bundle and then load on the new one. This causes the new bundle’s executable to be launched, but for some reason the bundle is still set to the old one. So for example, initWithBundle is called with the old bundle. Also, any resources fail to load, since they presumably didn’t exist in the old bundle.

The best-case scenario in this case is that the prefPane will load, but no images will be displayed. Image loading is non-fatal, so System Preferences.app will complain in the log about not finding the image resources, but otherwise continue normally. However, if there are any vital resources that need to be loaded, such as Core Data models, the prefPane will probably crash.

This scenario only affects the first launch, when the new prefPane replaces the old one. Afterwards, everything loads and works properly. But it’s hardly the best first impression to give to a user who’s upgrading.

So how to fix it? Since there’s no way to modify the way the prefPane is loaded, one viable solution is to skip that first load, quit System Preferences.app and launch it again. For the user, the process is seamless: after accepting the prefPane update, System Preferences.app will briefly disappear and reappear in the dock and the prePane will load. Apart from the dock icon, the rest of the process is unaffected in the eyes of the user.

Quitting and relaunching the prefPane has to be done with a small tool, which is located in the Resources folder of the new bundle. This is the code that does the magic, somewhere in initWithBundle (preferably the first item of business):

if ([[bundle bundleIdentifier] isEqual:OLD_BUNDLE_IDENTIFIER]) {	
		
	NSString *reloadPath = [[bundle bundlePath]
		stringByAppendingPathComponent:@"Contents/Resources/reload"];
	NSTask* task = [[NSTask alloc] init]; 
	[task setLaunchPath:reloadPath]; 
	[task setArguments:[NSArray arrayWithObject:
		[[NSBundle bundleForClass:[self class]] bundlePath]]]; 
	[task setStandardInput:[NSPipe pipe]]; 
	[task launch];
	[NSApp terminate:nil];
	[task release];
}

The path of the reload tool has to be manually set, rather than via NSBundle’s convenience methods, since they will give the wrong Resource folder. The reload tool takes one argument, which is the path of the new prefPane to launch. So essentially the prefPane sets up a task to launch itself, and then terminates.

The tool is very simple, all it does is launch the prefPane:

int main(int argc, char **argv) {
	
	char dummy; 
	read(STDIN_FILENO, &dummy, 1); 
	CFURLRef url = CFURLCreateFromFileSystemRepresentation(
		kCFAllocatorDefault, (UInt8*)argv[1], strlen(argv[1]), FALSE); 
	CFArrayRef url = CFArrayCreate(kCFAllocatorDefault, (const void**)&url,
		 1, NULL); 
	FSRef ref;
	OSStatus status = LSFindApplicationForInfo(0, 
		CFSTR("com.apple.systempreferences"), NULL, &ref, NULL)
	if ( status  == noErr) { 
		LSApplicationParameters parms = {0, kLSLaunchDefaults, &ref,
			 NULL, NULL, NULL, NULL}; 
		LSOpenURLsWithRole(url, kLSRolesAll, NULL, &parms, NULL, 0); 
	}
	CFRelease(url);
}

In Xcode, the target that builds the prefPane should have a dependency on the tool so that it is also built, and also copy the build result into the Resources folder.

Posted on Wednesday, May 12th, 00:16. Filed under: Automatic, Cocoa, Mac OS X, Xcode

There was a feature I wanted to implement in Automatic 2.0 that required registering the prefPane to handle a specific (custom) URL scheme to pass data into the app. After a lot of digging, I came to the inevitable conclusion: it can’t be done. This post describes both my findings regarding URL schemes in prefPanes and the workaround I used.

Normally, an app can register specific URL schemes with LaunchServices, telling the system that if a user clicks on a URL, it should be forwarded to that app. The information about the URL schemes is stored in the app’s Info.plist, under the CFBundleURLTypes key.

Unfortunately, that doesn’t work with prefPanes (as usual: the prefPane’s bundle is not the app’s bundle). What’s very interesting however, is that apparently Apple’s Accounts prefPane can handle URLs with the macosxserverinvite scheme.

So how does it do it? Looking at the Info.plist file for System Preferences.app, it normally registers the macosxserverinvite scheme, but also adds the key preference pane identifier, with a value of com.apple.preferences.users which is the bundle identifier for the Accounts prefPane. It seems that when System Preferences.app intercepts a registered URL, it forwards it to the prefPane whose bundle matches the preference pane identifier key-value. The big problem here is that this set up is not extensible: as is the norm for Apple apps, System Preferences.app is signed, which means no touching the Info.plist file to add additional URL schemes and redirects (and even without the signing, editing another app’s bundle is very naughty).

That’s where the trail ends. There doesn’t appear to be any way to register a URL scheme for a prefPane inside System Preferences.app. However, there is a workaround: use a helper app.

The process goes like this: register a background helper app to handle the URL, and when the helper intercepts a URL, either process the information itself, or store the data and then launch the prefPane. Of course, because the helper can only launch the prefPane, but not provide it with any other information, it is the prefPane’s responsibility to check every time it launches if there is any URL data stored that hasn’t been handled.

It’s quite a hassle, but the end result for the user is seamless: click on the URL, the prefPane launches and takes appropriate action.

Posted on Thursday, April 22nd, 04:05. Filed under: Automatic, Cocoa, Mac OS X, Xcode

In Automatic 1.x, there was an option called “Download every episode once”. If enabled, it would make sure that each episode in a series of episodic content would be downloaded only once, regardless of how many times it (re)appeared in the feed.

There was a catch, however: it only worked if the subscription was set up to match a single series. If the subscription was matching multiple series, and the episode numbers overlapped, there were false negatives. This was a one of the most common issues users had with subscriptions.

With 2.0, this feature can still be found for Custom subscriptions under the name “Try to download every episode once”. But it’s been upgraded to be a little smarter: it can now differentiate between episode numbers that belong to different series. So if a Custom subscription is grabbing multiple series, this option can now safely be enabled.

As an aside, the “Unless tagged as ‘proper’ or ‘repack’” option has been removed, and these tags are now universally respected for all subscriptions.

Posted on Saturday, April 17th, 23:57. Filed under: Automatic, Features, Mac OS X

« Previous PageNext Page »