Wednesday, January 11, 2012

Part 2 - Adding missing keyboard shortcuts

The ultimate aim of this project was to end up with a situation where for every button on the on-screen remote control there was an equivalent button on the physical Harmony remote control. This would even be an advantage over the Slingcatcher remote control where certain 'special' buttons could only be accessed through an on-screen menu.

However, in order to achieve this, we are relying on a keyboard shortcut existing for every button on the on-screen remote. This is because later on we are going to use the Remote Buddy software to map button presses on the Harmony remote to these keyboard shortcuts to control the remote satellite/cable box.

So the first thing you need to do is check to see which keyboard shortcuts are present and which, if any, are missing. The easiest way to do this is simply to watch your Slingbox at watch.slingbox.com, click on the 'Remote' button and then hover the mouse pointer over each button in turn. If there is a keyboard shortcut mapped then it will tell you in brackets after the button name, otherwise there will be nothing in brackets.

Since we are going to need to know later on which button is assigned to which keyboard shortcut, I suggest writing them all down at this point.

My TV provider in the UK is Sky+ HD and here is what I wrote down for my on-screen remote:

Power on/off (Ctrl+Shift+P)
The Sky+ HD Remote
Sky (Ctrl+Shift+S)
Box Office
Services
Guide (G)
Interactive
Mute (Cmd+Shift+M)
Info (I)
Volume Up (Cmd+up)
Volumne Down (Cmd+down)
Channel Up (=)
Channel Down (-)
Text
Back Up
Help
Rewind (R)
Fast Forward (F)
Pause (U)
Play (P)
Record (Ctrl+Shift+R)
Stop (S)
Red (Ctrl+Shift+D)
Green (Ctrl+Shift+G)
Yellow (Ctrl+Shift+Y)
Blue (Ctrl+Shift+B)
Numbers (0-9)

As you can see, the Box Office, Services, Interactive, Text, Back Up and Help buttons didn't have a keyboard shortcut assigned. The lack of a Back Up button is a particular problem as it means there is no easy way of exiting from the EPG!

With the Slingbox there are two separate parts to the remote control side of things. There are the binary file(s) that are loaded onto the Slingbox and which tells the Slingbox which IR codes to send to your satellite/cable box via the IR transmitters, and then there are the files that define the visual appearance of the remote control inside the web player plugin and desktop player software.

In this case, it is only the latter we are interested in here since it turns out that the keyboard shortcuts are associated with the button graphics in the skin and have nothing to do with the files loaded onto the Slingbox during the setup process.

So, where to start with adding the missing shortcuts? Fortunately, those ever-helpful folk at the Placeshifting Enthusiasts website have written a detailed tutorial that covers the process of editing these skin files.

You can find it here:

How To Edit Your Remote Skin

The article is slightly dated now in that it makes a few references to this procedure not being possible for the web player plugin, but fortunately I didn't find this to be the case.

In case you're too lazy to read the whole tutorial (which covers more than just adding missing keyboard shortcuts), here is a condensed version to suit our needs:

1) navigate to where your remote control skin is stored and identify your '.spr' file.

Since we are dealing with the Mac web player plugin here, the remote files can be found here:

/Users/<username>/Library/Application Support/SlingMedia/Remotes

(Obviously you need to substitute <username> for the short form of your OS X username.)

In my case, since I'm using a Sky+ HD box, it was the file 'SkyHD.spr' that I was interested in.

2) go back to placeshiftingenthusiasts.com and search for the equivalent '.zip' file

Essentially the problem here is that we can't edit the 'SkyHD.spr' file directly because these days Sling encrypt these files (apparently they used not to), so instead we need to find the file 'SkyHD.zip' that the folks at PCE have created and archived here:

Slingplayer Remote Skin Files

Once you've found the right file, unzip this somewhere on your machine.

3) still at placeshiftingenthusiasts.com, locate the global 'property.xml' file

Slingplayer 'property.xml' file

Now place this file inside the folder containing all the files you unzipped earlier.

4) double-click the 'remote.xml' file to open it, or otherwise open it in TextEdit

This file contains the mappings and keyboard shortcuts for your remote and what we need to do is locate the section containing the keyboard shortcuts and add the missing ones.

In my case, this section was at the end and here is how my 'remote.xml' looks after I've edited it. I've highlighted the ones I added in blue:

Adding the missing keyboard shortcuts
As you can see, I have added extra lines for each of the keyboard shortcuts that I discovered were missing earlier.

One thing to be careful of here is making sure you don't re-assign the same keyboard shortcut to more than one button on the remote. Importantly, when checking for such clashes, you also need to check the 'property.xml' file for keyboard shortcut assignments too as many of the basic ones are defined in this file.

5) zip up all the remote skin files into a replacement ZIP archive

Now that you've added the missing shortcuts you just need to zip them back up. You can do this by selecting them all and then right-clicking on the selection and choosing 'Compress X items'.

You will need to rename the 'Archive.zip' file that this operation produces so that it matches the name of the '.zip' file you downloaded. In my case this was 'SkyHD.zip'.

However, before we can use this replacement file we need to change its extension from '.zip' to '.spr' so that the web player plugin can find it.

The best way to do this is to select it, press Cmd+I to pop-up its info and then in the 'Name & Extension' edit box just delete the '.zip' and replace it with '.spr'.

You will probably get a prompt asking you if you really want to do this, to which the answer is a resounding yes!

6) copy the new '.spr' file over the top of the old '.spr' file and lock it

I would recommend that before you do this that you backup the old '.spr' file inside the Remotes folder, just in case something goes wrong.

Then you just need to replace the old '.spr' file (in our case 'SkyHD.spr') with the one we have created.

Unfortunately I found that this alone was not enough to force the web player plugin to use the new remote - for some reason it will try and override your newly-created file with the one from Sling's servers and the only way I have found to stop this happening is to lock the new one. I'm guessing there is some kind of checking done that means the plugin thinks the one stored on Sling's servers is preferred. (Perhaps Sling could make a small but useful change here - how about making the plugin search first for 'SkyHD.zip' and if it finds that then use it instead?)

Anyway, the easiest way to lock it is to select it, chose Cmd+I again to popup its info and then tick the 'Locked' check box.

Now all that remains is to test what you have done by going to watch.slingbox.com again (it might be wise to quit and re-open your browser first), click on the 'Remote' button and verify that when you hover over all the buttons that the correct keyboard shortcuts are now shown!

Wednesday, December 28, 2011

Part 1 - Automating watch.slingbox.com

The first step towards creating our "Slingcatcher alternative" is to write a program that will launch a web browser, navigate to the correct page, connect to a Slingbox of our choice from the directory (if there is more than one to choose from) and then switch into full screen mode.

The idea is that we will then execute this program when the user chooses the appropriate option using their remote control, but in part 1 we will just look at constructing the program itself and not worry about how we are going to trigger it. That comes later!

One of the nice things about using OS X is that so much can be achieved using AppleScript. In a nutshell, AppleScript allows us to write simple English-style statements to control applications. These can be basic commands like launching or quitting applications, to more complex operations such as opening and manipulating documents inside an application. It turns out that everything we need to do for this project can be done with AppleScript.

For example, here is what we need to write to tell the Safari web browser to launch or if already launched to become the application with the focus:






If you load up the AppleScript Editor (you can find this inside Applications/Utilities) and type these lines into the main area and then press the 'Run' button then you can see this for yourself.

Now the precise possibilities achievable using AppleScript to control a program depends on what support has been built into the program, but even in applications where little support has been built in there is something known as "GUI Scripting" which basically means you write AppleScript to 'click' on certain buttons inside the application in order to control it. The application itself need have no knowledge of who or what is doing the 'clicking' - it just reacts in the usual way.

Anyway, returning to the subject in hand, having often used the watch.slingbox.com page to watch my Slingbox I was familiar with the process involved, assuming I had previously signed into my Sling account and told the browser to keep me signed in:

  • by navigating to the page, it would automatically start connecting to the last Slingbox viewed
  • I could hit Cancel at this point if I didn't want to view this Slingbox, or I could let it connect
  • If I hit 'Cancel' I would then be presented with a list of Slingboxes to choose from
  • I could then click on a Slingbox and it would then attempt to connect to this one
  • If I happened to be viewing the same Slingbox on another device I'd need to click 'Yes' when prompted, to override the other device
  • Once connected, I would need to click on the 'Full Screen' button to switch into full screen
  • If I became disconnected, it would switch out of 'Full Screen' and give me the option to re-connect
  • Quitting the browser or closing the window would be enough to disconnect from the Slingbox

So my aim was to write some AppleScript which would be able to handle the above process automatically without needing keyboard or mouse input and thus would be suitable for triggering via a hardware remote control.

In order to do this it was clear that the script would need to have some sort of knowledge of the state of the web page at any given time - for example, in order to automatically 'click' on the 'Full Screen' button it would need to know that this button was visible and depending on the method used to 'click' it might need to know its position on the screen.

The two browsers I looked at were the default Apple Safari browser shipped with OS X and also Google Chrome. It turned out that both would be useful. Safari provided the best AppleScript support and would thus be the basis for this project, but I discovered that Chrome could be very a useful testing/inspection tool.

In Chrome it is possible to choose the menu 'View' -> 'Developer' -> 'Developer Tools' and then by right-clicking on any item on the web page and choosing 'Inspect Element' you can see exactly how that item has been constructed in HTML-speak. Even better, by choosing the 'JavaScript Console' option you can type in JavaScript commands directly to further query the different HTML elements and generally try things out that can later be called from the AppleScript program.

Google Chrome Developer Tools

Using this method I was able to identify the key elements on the page that would indicate which 'state' the page was in. It was then a case of writing the corresponding AppleScript to tell Safari to execute Javascript on the page to retrieve back this information.

For example, here is some AppleScript that registers a JavaScript function to determine if the 'Full Screen' button is visible on the page:













To call this function from AppleScript we just execute some more JavaScript and store the return value in a variable:







In a similar manner, we can then write other functions to identify the presence of other key elements on the page. So using this method, now that we were able to identify the state of the page, we needed a way for the script 'click' on the buttons themselves depending on where in the overall process we are. 

This proved a bit trickier. Initially I took the approach of directly issuing mouse events onto the elements on the web page. A bit of Googling revealed how to do this, but I found this to be a little unreliable when applied to this web page. Sometimes the events just didn't seem to fire and (for example) the script would sometimes not click on the 'Full Screen' button.

So I thought a more reliable approach would be to address it at a different level and actually have the script move and click the mouse pointer at the correct co-ordinates on the screen and then let the web page react in the same way it would had this been the user doing the clicking. It turns out that AppleScript provides some options for doing this, but unfortunately I couldn't get these to work reliably either! A bit more Googling revealed that others had experienced problems too.

In the end, I was finally able to achieve what I wanted via a useful utility called 'cliclick' which you can download from here:


Once downloaded, you will need to copy the file 'cliclick' into your 'usr/local/bin' directory. If the 'bin' directory doesn't exist, then you will need to create it. You may need to enter your password to do this.

So what is this program? Well, this little gem is a small shell program which when invoked with the correct arguments will move the mouse pointer to a certain location and issue a click event. Since it is possible to call shell script from AppleScript, I was able to write a small function that would use this little program to click anywhere on the screen.

So piecing it all together, I was able to write an AppleScript program that could do everything I needed it to. In order to provide maximum flexibility I have allowed the script to take in an optional argument - the name of a Slingbox. If this argument is not supplied, then the script will just allow the web page to auto connect to the last Slingbox viewed. However, if a valid name is passed in (this must match the name shown on the Slingbox directory page) then it will instead automatically view this Slingbox instead.

Now rather than go into great detail about how the script works I've instead commented each section - if there are any expert scripters out there feel free to suggest improvements. Until a couple of weeks ago I hadn't written a line of AppleScript so I'm sure there are ways it can be improved!

You can download the script from here:


Once downloaded, you can double click on it to load it up into AppleScript editor and then click the 'Run' button to execute it.

Note that the script relies on the 'cliclick' program mentioned above having been installed in 'usr/local/bin'. If you installed it elsewhere then you will need to modify the AppleScript function 'click_mouse' to refer to its correct location. You can find this function near the bottom of the AppleScript.

As mentioned earlier, this system also relies on you being logged into your Sling account in Safari - the script will simply wait and do nothing if the page throws up the login page.

One other thing you may need to do before you run the script is to tick the 'Enable access for assistive devices' box inside 'System Preferences' -> 'Universal Access' -> 'Mouse & Trackpad'. If you don't do this, the 'cliclick' program may not work and thus neither will the script.

Finally, I have only tested the script on OS X 10.7.2 Lion.

So that's part 1 - In part 2 we will take a slight but necessary divergence to tackle the issue of the on-screen virtual remote missing some keyboard shortcuts. To build a fully operational system we need every key on the remote to have an equivalent keyboard shortcut.

Monday, December 26, 2011

Catching my Sling

As someone living away from my "home" country I've become quite used to using Sling Media's Slingbox devices to stream Sky TV from our flat in the UK over here to Istanbul via the Internet.

The Slingbox viewing page
For those unaware, a Slingbox is a device that you plug into your home network and also connects to your satellite or cable TV box. This clever little box can then stream video and sound around your network or across the Internet where it can be viewed on another device, such as a PC, that knows how to decode the stream. To complete the picture, the remote device can also send commands over the network that the Slingbox receives and converts to IR codes using a pair of IR transmitters which are placed close to the IR sensor on the Satellite box. This means that the remote viewer can have full control over the satellite/cable box, change channel, access the EPG, etc. This is what has become known in the industry as "place shifting" and the Slingbox has become one of my favourite gadgets of all time.

Now originally with the Slingbox it was only possible to view your TV stream using either the PC or Mac Slingplayer desktop software, but Sling gradually expanded the player application to mobile devices such as the iPhone, iPad, Android, Windows phone etc and have also established a web page where you can view your TV from your computer's browser via a proprietary plugin.

A few years ago they also created a device known as the Slingcatcher which, in my opinion, gave the best and most seamless viewing experience, largely because it did away with the need to fiddle about controlling your PC with the mouse when all you wanted to do was change channel. It managed this by providing a hardware remote which essentially gave you the true 'place shifting' experience of watching your remote satellite box and having a remote control in your hand that would allow you to control it. For me this has been ideal as I can put on some UK TV very easily for my young daughter for example, without having to open up the laptop.

Lately though, Sling Media seems to have taken a slightly different direction. For a start, they ditched the Slingcatcher, although for whatever reason they never announced this and have instead allowed their customers to discover this gradually for themselves by quietly removing references to it from their site. You can still find Slingcatchers from places like eBay but they now command a premium price. To "replace" the Slingcatcher they're currently integrating their player into various other hardware devices, the first of which has been the Boxee and Google TV.

The ill-fated Slingcatcher
They have also seemingly given up development on the Windows and Mac Slingplayer desktop software - neither have seen updates for ages - instead appearing to see the web plugin as the primary viewing method for your computer and the one they update regularly with fixes and enhancements.

The early signs from these most recent of ventures though are that while they are creating player applications for a large number of devices/platforms - they even have one for the ubiquitous Facebook platform - they perhaps aren't really interested in creating the most seamless and intuitive place shifting experience.

Now to be fair, I'm probably not their main target audience. I suspect for Sling Media it's more about watching your TV on-the-go, rather than catering for people like me who want to fully reproduce the native experience in a different location and I can understand that.

So anyway, to cut a very long story slightly shorter the purpose of my first few blogs is going to be to outline a mechanism by which its possible to set up a functional replacement for the Slingcatcher on a Mac Mini in as an elegant a fashion as possible so that when and if my Slingcatcher packs up, there is a viable alternative.

There is also the fact that the Slingcatcher has a maximum output resolution of 1280 x 540 which is somewhat less than the 1920 x 544 that the Slingbox Pro-HD is capable of streaming and I'd like to be able to get the best possible stream on my TV now that I finally able to get a fast Fibre-based upload speed from my UK flat.

The first blog will describe how to create a small application using AppleScript which can be used to automatically launch Safari, navigate to the watch.slingbox.com web page, connect to a Slingbox of our choosing (if there is more than one) and switch into full screen mode.

The second blog will detail how to ensure that the on-screen "virtual" remote control used by the web plugin has keyboard shortcuts set for all the buttons on the remote that we want to control. If your remote already has all the shortcut keys you require then you can skip this step.

The third blog will show how you can use the popular Remote Buddy software to configure an Apple Remote control to trigger the keyboard shortcuts and thus give you control over the remote satellite/cable box.

The fourth and final blog will show how you can take it a step further and integrate a Harmony universal remote into the system and use it to provide a fully fledged remote control for the remote satellite/cable box.

Finally, a special thanks to fellow Slinger Yoav Freiberger for helping test some of this stuff out!