Grab content from a web browser in your Mac app

January 2014

One of my favorite features of Tapetrap is its ability to subscribe to a website while surfing the web with your browser. Instead of looking for the RSS feed manually and copy-pasting the link, you can click a button and Tapetrap will find and add the feed for you. In this article I want to go over why I think thatā€™s awesome and how it works. The source code for the URL grabbing is available on GitHub.

Adding feeds from your web browser in Tapetrap

Not a browser plugin

Iā€™ve made and use a few browser extensions. Theyā€™re neat little applications that take an insane amount of work to maintain. While some code can be shared you will need to tailer parts of the extension for each browser specifically.

For Tapetrap, I chose to make a system wide browser extension in the form of an icon in the menu bar that ā€œjust worksā€ with the active web browser when clicked. This means users donā€™t have to install anything extra and I donā€™t have to create a plugin per browser. I canā€™t say Iā€™m the first one to do something like this, but it works particularly well for Tapetrap.

Add feeds while surfing the web

Of course there are downsides to using this approach too. Itā€™s impossible to manipulate the DOM inside the browser or execute other more context aware methods. Itā€™s fine for getting basic information, though.

How grabbing works

This is where it gets a little technical. I combined a basic menu bar app with my own URL grabber code, called DCOURLGrabber, to get the URL from the web browser that was last active.

Iā€™ll skip the menu bar icon part. There are plenty of good tutorials that explain all you need. Instead Iā€™ll talk about how to interact with the web browser.

AppleScript

Yep, AppleScript. Often used to automate tedious tasks, itā€™s also a great way to interface with other applications. For DCOURLGrabber I focussed on getting the URL from the selected tab of the key window of the web browser that was last active. This is the AppleScript for getting the URL in Google Chrome:

tell application "Google Chrome"
  get URL of active tab of first window
end tell

Simple enough right? For Safari and Opera the command are very similar. The one for Firefox is a little longer.

tell application "Firefox" to activate
tell application "System Events"
  keystroke "l" using command down
  keystroke "c" using command down
end tell
delay 0.5
the clipboard

Hopefully theyā€™ll switch to a straightforward approach in a future update. In any case, after running these scripts they present the current URL of the browser window.

Objective-C

To run this in Objective-C, create a new Mac project in XCode, paste in the next piece of code in the applicationDidFinishLaunching: method and thatā€™s it.

// The script to run. You could also load this from a file as in DCOURLGrabber
NSString *chromeScript =
@"tell application \"Google Chrome\"\n"
"  get URL of active tab of first window\n"
"end tell";

// Load the script
NSAppleScript *script = [[NSAppleScript alloc] initWithSource:chromeScript];
    
// Grab URL using AppleScript
NSDictionary *scriptExecuteError;
NSAppleEventDescriptor *result = [script executeAndReturnError:&scriptExecuteError];
if(scriptExecuteError) {

  // Failed
  NSLog(@"Error: %@", scriptExecuteError);

} else {

  NSLog(@"Output: %@", result.stringValue);

}

Using DCOURLGrabber it becomes even easier. Check the GitHub page for more documentation.

DCOURLGrabber *grabber = [[DCOURLGrabber alloc] init];
NSURL *url = [grabber grabURLFromBundleID:@"com.google.Chrome" withError:&grabError];
if(grabError) {
    NSLog(@"Failed to retrieve URL: %@", grabError);
} else {
    NSLog(@"Got URL: %@", url.absoluteString);
}

Getting the RSS/Atom URL

Websites that value their feeds will link to it from their website. Not only with the well-known orange button, but also through a meta tag in the source code of the website. This gives apps like Tapetrap a way of retrieving it.

The GameKings website has this setup correctly. Inspecting the source of http://gamekings.tv reveals the following lines near the top of the document.

<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="https://www.gamekings.tv/feed/" />
<link rel="alternate" type="text/xml" title="RSS .92" href="https://www.gamekings.tv/feed/rss/" />
<link rel="alternate" type="application/atom+xml" title="Atom 1.0" href="https://www.gamekings.tv/feed/atom/" />
<link rel="alternate" type="application/rss+xml" title="Gamekings Video's RSS Feed" href="https://www.gamekings.tv/rss?cat=3">
<link rel="alternate" type="application/rss+xml" title="Gamekings Nieuws RSS Feed" href="https://www.gamekings.tv/rss?cat=18">

All links point to RSS feeds. There are some similarities between the lines. Using these conventions, itā€™s easy to extract them in code. Even easier with OCGumbo, which is a HTML5 parser. It converts RSS into Objective-C objects.

The following lines of code parse a simple HTML page, check the ā€˜typeā€™ parameter of the ā€˜linkā€™ meta tag for either application/rss+xml, application/atom+xml, rss+xml or atom+xml and log the link when it matches.

// Create an array that contains the strings that can appear in the 'type' property
NSArray *linkTypeFeedIndicators = [NSArray arrayWithObjects:@"application/rss+xml", @"application/atom+xml", @"rss+xml", @"atom+xml", nil];

NSString *htmlString =
@"<html><head>"
"<link rel='alternate' type='application/rss+xml' title='RSS 2.0' href='http://www.gamekings.tv/feed/' />"
"</head><body>"
"<h1>Feed discovery experiment</h1>"
"<p>Just testing ;).</p>"
"</body></html>";

// Load the document from a string containing HTML
OCGumboDocument *document = [[OCGumboDocument alloc] initWithHTMLString:htmlString];
OCGumboElement *root = document.rootElement;

// Loop through all 'link' tags
[root.Query(@"link") enumerateObjectsUsingBlock:^(OCGumboElement *element, NSUInteger idx, BOOL *stop) {
    NSString *type = [element.attr(@"type") stringByRemovingNewLinesAndWhitespace];
    
    // Check if the type is equal to that of a RSS/Atom feed
    if([linkTypeFeedIndicators containsObject:type]) {
        NSString *feedURLString = element.attr(@"href");
        NSLog(@"Found a feed: %@", feedURLString);
    }
}];

With the URL of the RSS feed in hand, the road is clear to analyze its content using a RSS parser, or maybe use the URL for something different entirely.

Real world example

You can download Tapetrap to get a feel of how this works. The app is now in public beta and free to use. Also let me know what you think and help improve it!

I love watching web videos

January 2014

Tapetrap header

Online videos are my favorite work break. I might watch an episode of Star Trek TNG during lunch, but I watch far more online videos while I wait for some stuff to compile or just to take my mind off what Iā€™m doing.

Tapetrap makes sure I spend less time searching and more time watching these videos. I use it daily and love how it works. Now I need your help to make it even better.

The videos I like to watch arenā€™t available from a single website. YouTube has a lot, but definitly not everything. Maybe even less in the future, with the copyright claims a lot of video game oriented channels had to deal with lately. I wanted to get away from browsing to every single website independently, deciding what I wanted to watch and then forgetting which clips I had already seen. Or making an account for every site to overcome that last problem.

Browsing in Tapetrap

Tapetrap will hold all my favorite sites, make it easy to add new ones, play videos and remembers which Iā€™ve already seen. When I have 5-30 minutes to spare, it gives me a quick overview of whatā€™s available and ten seconds later Iā€™m watching a video. I donā€™t even have to check where I left off if itā€™s a series. Itā€™s pretty awesome really.

Especially while Tapetrapā€™s in beta, Iā€™m looking for ways to improve the experience and add features. If youā€™re like me and follow a bunch of skateboarding channels on YouTube, TED Talks, Funny or Die, Artsy Vimeo Channels, Spoony etc. etc., download Tapetrap and let me know what you think.

Keep track of your web video feeds with Tapetrap

October 2013

If youā€™re anything like me, you spend quite some time reading, listening to and watching various things online. It would be impossible to organize all this information without the use of a few excellent apps, like Reeder for news and Instacast for podcasts.

Web videos are harder to manage. Despite popular believe, not everything is available on YouTube or Vimeo. In need of a dedicated tool to keep up with online videos, no matter where theyā€™re hosted, Iā€™ve made a brand new app!

Keep track of your web video feeds with Tapetrap

Tapetrap will give you instant access to your favorite webisodes, lets you know when a new item comes out and keeps track of which youā€™ve seen.

For me, this means I can watch VICE, Zero Punctuation, the AVGN, Conanā€™s Clueless Gamer, the Spoony Experiment, Gamekings, Christopher Walkenthrough, TED talks and Uitzending Gemist all in one app.

Itā€™s been in development for the past month and, not too tease you too much, is working great! That said, itā€™s not done yet. I still want to polish a few features before putting out a public version. Until then, subscribe to the mailing list to stay up to date and help testing!