Sunday 30 May 2010

A little music

Looking at the code in home-screen.js I can see that it downloads from vieracast.eu (EU market) vieracast.tv (US market) depending on where you are. I used my download.sh script created earlier to download similar files from the US server and compared them. I noticed they have Amazon video player, Pandora music player etc. I tried to get these working, unfortunately they're restricted by geographical IP address. This can probably be proxies around, but for now I looked a the code and how Pandora plays music.

In home-screen.js, I added the following code after the function disconnect_bplayer(): -

disconnect_bplayer();

var pd_musicPlayer = new MusicPlayer({});
pd_musicPlayer.connect( AudioDev );
pd_musicPlayer.set_url( "http://www.mfiles.co.uk/mp3-downloads/Fur-Elise.mp3" );
pd_musicPlayer.play2();


This code disconnects the broadcast player (i.e. the embedded TV player in the middle of the screen) and plays a piece of music at the specified url in the background. Beautiful :D

I've tried this with various file formats, it works fine with mp3 and aac files. My hope was that it will be possible to point it to an internet radio stream, however it seems that the MusicPlayer() class is not happy with files that don't specify a content length :( It may be possible to spoof a length in the HTTP headers, but I haven't tried that as yet.

Feeding an example video

My first attempt to do something "interesting" was to intercept the youtube plugin and force it to point to a different video somewhere else on the web. Looking at what is downloaded, we can see that one of the files downloaded is vieracast.eu/youtube/featured. This file contains a list of the "featured" videos in a feed. If we replace this, we can point the youtube player to other media.

Create the file /var/www/vieracast.eu/youtube/featured to contain: -

[
{"title": "This is the title",
"author":"nobody",
"views":1,
"rating_average":5,
"rating_max":5,
"duration":1,
"thumb0":"http://myserver.com/0.jpg",
"thumb1":"http://myserver.com/1.jpg",
"thumb2":"http://myserver.com/2.jpg",
"thumb3":"http://myserver.com/3.jpg",
"content":"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",
},
]


Then run the youtube plugin, choose featured, and there will be just your one video (with no thumbnail since the URL's are bogus). View the video and it plays the video stored in "content"!!!

This is only a hack and an ultimate solution would have a separate plugin, but it proves the theory.

Logging Errors and Information

So, we've established that it's a JavaScript environment, so when changing it'd be nice to see any error messages. At Panasonic they presumably have development kit that has a "console", so they can see error messages. My telly didn't come with that strangely!

I haven't yet figured out a way of capturing all JavaScript errors, but I have got a way of logging some information so at least you can track progress through the code and output debugging information.

Firstly, take a copy of home-screen.js to modify and add the following at the start: -

console.log = function (msg) {

http_request({ url: "http://X.X.X.X/log.php?message=" + msg,
method: "GET",
sync: false,
onload: NULL_FUNCTION,
});

}

replace X.X.X.X with the IP address of your Apache server.

Now find the line that reads "var level = " and change the number to 4.

Below this line you will see function definitions for fatal, error, warn and info. These are called within the script, which call console.log, which we've just overridden to perform a HTTP get from a (yet non-existent) PHP file on our web server. I think it's a good idea to duplicate one of these, call it something unique (mydebug for example) and change what it outputs to make it easier to find your debug messages in the code.

Once you've done this, you need to create /var/www/log.php containing the following: -

<?php
echo $_REQUEST['message'];
$file = fopen("/var/logs/console.log","a");
fwrite($file,strftime('%c') . " : " . $_REQUEST['message'] . "\n");
fclose($file);
?>

Now, whenever your script calls console.log, it'll be overridden to request log.php from the webserver, passing the message as a parameter. The log.php will then write any output to console.log. Test this by browsing to http://yourserver/log.php?message=test and then to http://yourserver/console.log

You will now see all the informational messages that panasonic have added, and can also (assuming you created a function) call mydebug (or whatever) with your own progress and informational messages.

If anyone figures out a way to somehow override and capture syntax or runtime errors in a similar way I'd love to know! For now debugging basically includes adding mydebug() calls all over the place so I know how far through the code it's got!

"Slurping" data

I just came up with a better way to download all the code. Instead of using our download.sh to acquire every single file one by one, add the following to mirror_and_redirect.sh, one line, after the "echo" in the No Match section: -

wget --directory-prefix /var/www/slurped -a /var/log/squid/slurping.log -t 1 -nc -xU "XXXXXXXX" $url

Again, replace the XXXXXXXX's with your User Agent string.

Create a directory /var/www/slurped and make it writable by your proxy user.

Now, every time your device accesses a file from panasonic (or anywhere else for that matter), it will be pulled down automatically into this holding area. Any files you want to modify, simply move it to it's equivalent directory in /var/www. e.g. cp /var/www/slurped/vieracast.eu/data/home-screen.js /var/www/vieracast.eu/data/home-screen.js (after mkdir obviously :D )

NOTE: This will slow down your experience, since it's downloading everything twice! Also, it doesn't pull down everything (some URL's are too long - but that's handy because it would be pulling down full mpeg files!). Just keep an eye on /var/log/squid/slurping.log for any errors.

Saturday 29 May 2010

Downloading content to modify

My previous post showed how I setup Apache and Squid to serve updated pages, but as of yet nothing has been modified. Assuming Apache and Squid are working as described, the next stage is to download some content, inspect and modify it.

When accessing Viera Cast via the proxy, all content will just be proxied directly to Panasonic servers, this is because we have no local copies. Have a look at /var/log/squid/mirror_and_redirect.log and you will see what files were served by our script. The first you will see (on a European device) will be http://vieracast.eu/data/home-screen.js. This is the start page.

Try and access this from your browser and you will see a 404 Not Found error page. The servers expect your browser (or rather the device) to send a user agent to identify it as a Panasonic device. This is where the useragent.log we configured comes in. Look at /var/log/squid/useragent.log and you will see a big list of gobbledigook. These are seemingly random strings of characters which change with every file. Thankfully we don't need to know what they say, we can it seems choose any one of those strings and "spoof" a Panasonic device.

This bit is optional - it just demonstrates that the User Agent string works. If you have Firefox, install User Agent Switcher. Create a "test" user agent and paste any one of those strings into the user agent. Try again to browse to your home-screen.js and you will see JavaScript!

Now that you know the user agent works, we need to download the home-screen.js to our server to modify. Create a script (and make it executable) somewhere called download.sh containing the following (on one line): -

wget --directory-prefix /var/www -t 1 -nc -xU "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" http://vieracast.eu/$1

Replace the XXXXXXX with one of your User Agent strings from useragent.log.

Now run download.sh data/home-screen.js

You will see it download the file to /var/www/vieracast.eu/data/home-screen.js

If you access Viera Cast from your device now, you will see from your mirror_and_redirect.log that it served up the local version instead i.e. http://localhost/vieracast.eu/data/home-screen.js

In my next post I'll cover some basic modifications.

Setting up a Development Environment

In order to perform any development, you need a development environment. How you choose to setup yours is up to you, however below I will detail how I did mine. Whichever way you choose you need to do 4 things: -
  • Provide a web server to serve up your modified content.
  • Create a web proxy server to redirect access to your web server.
  • Point your Panasonic device to your web proxy.
  • Download and host content from Panasonic's Viera Cast servers and modify them to your needs. This will be covered in the next post.
For my current environment I'm using Ubuntu Linux since it provides a full set of features including Apache 2 (web server) and Squid (web proxy). In future I intend to replicate this setup on my Western Digital MyBook World (NAS unit), which has a much smaller power footprint and is always-on. In theory the same should be possible for other customisable NAS units (Synology, Q-NAP et al).


Web Server

The web server I use is Apache 2. For development purposes I'm using a bog-standard out-of-the-box installation. In Ubuntu this serves pages from /var/www on port 80.


Web Proxy

The web proxy I'm using is Squid (default port 3128). I modified this slightly (by editing /etc/squid/squid.conf) to minimize the footprint as follows: -
  • Add "http_access allow all" (bad practice but this is development in my own home - You need to add something that lets your TV/device and development PC access the proxy).
  • Add "cache_dir null /tmp" and "maximum_object_size 0 KB" (to disable disk cache - we only care about the URL redirection features so this saves space).
  • Add "useragent_log /var/log/squid/useragent.log" (the reason will become clear soon).
  • Add "url_rewrite_program /etc/squid/mirror_and_redirect.sh" (this points to a redirect script we will create)
I then created a URL rewrite program called /etc/squid/mirror_and_redirect.sh (and made it executable) containing the following: -

#!/bin/bash

while read url rest; do
filename=`echo $url | sed 's^http://^^g' | sed 's^?.*^^g'`
if [ -f /var/www/$filename ]; then
# We found a matching local file to replace, so redirect to it and log the redirect.
echo "http://localhost/$filename"
echo "http://localhost/$filename" >> /var/log/squid/mirror_and_redirect.log
else
# No match, so don't modify the URL and log the URL.
echo
echo "$url" >> /var/log/squid/mirror_and_redirect.log
fi
done

The purpose of this script is a follows. Every HTTP request passed via our proxy is parsed by the script and compared against the contents of /var/www. If a matching file exists then it adds a redirect to http://localhost/our_replacement_file to redirect the client (i.e. the Panasonic device) to our local modified file. It logs all this information to mirror_and_redirect.log so we can see what's been served locally and what's been passed through.


Configure TV

Finally I configured my TV to access the web via the proxy. On my Panasonic G20 Plasma this is accessed under Menu...Setup...Network Setup...Proxy Settings. I set the address to the IP address of my Ubuntu server and port to 3128 (Squid). How you do yours depends on what you've got. If you can't figure it out, you probably shouldn't go any further :D

Assuming Squid is now working, Viera Cast should work as normal on your device. And now the fun begins...

Welcome

Hi, a quick intro to the intention of this blog. I like many others have a Panasonic TV which has Viera Cast functionality allowing access to a limited range of streaming media direct from the internet. This is great in principle, however in practice it's limited to YouTube and a few others.

I'd like to discover how to expand this functionality on my set, and so this blog is two-fold. My knowledge and time I can spend on this work is limited, so I aim to show what I can do so far, with the hope that others with the time and ability can work from that and hopefully help improve what we can do.