download my resumeashley@mervyngraham.com

Ashley Mervyn Graham

rsnapshot Over a Network

Scenario

There are many ways to stream media to your PS3. I, personally, prefer MediaTomb, others prefer PS3MediaServer.

This guide is going to aide you–and me in the future–on how to setup MediaTomb on Ubuntu 10.04LTS

Installing MediaTomb

Firstly, you need to install it, however the version that comes with 10.04 doesn’t have JavaScript support (for various nerdy reasons that we really don’t care about) which means that the directory listing sent to your PS3–and the web interface–is rather dull.

So, we’re going to need to enable another repository for APT to pull from. Luckily, one fine fellow created such a repository for us to use.

Add the repository to APT with: sudo add-apt-repository ppa:jinto/mediatomb-js which will grab the authorization key for this repository, and remember it for future reference; then update your repository listing: sudo apt-get update.

Finally install: sudo apt-get install mediatomb which will grab all the dependencies for you.

Configuration

MediaTomb should now be working and accessible from your PS3. Start up your PS3, head over to the “video” icon (typically the icon to the left of where the PS3 dumps you upon boot) and “mediatomb” should be listed.

The supplied configuration file doesn’t enable a few options we need (well, not need) for PS3 support, nor does it enable javascript. So edit the configuration file with your favorite editor: sudo ne /etc/mediatomb/config.xml and make the following changes.

Firstly I supply the port mediatomb should use, it makes it easier down the line and when debugging. Find the line of /etc/mediatomb/config.xml that looks like this:

<server>
		

Change it to look like this:

<server>
    <port>49152</port>

You can pick any port you wish, however this is the port mediatomb uses by default.

Second for–alleged–PS3 support (meaning I’ve gotten it to work without this change, however we should be safe with it enabled):

Find the line that matches the following:

<protocolInfo extend='no'/><!-- For PS3 support change to 'yes' -->

And change it to:

<protocolInfo extend='yes'/><!-- For PS3 support change to 'yes' -->

Thirdly we enable javascript layout instead of the supplied dull one. Find this bit of code:

<scripting script-charset='UTF-8'>
   <common-script>/usr/share/mediatomb/js/common.js</common-script>
   <playlist-script>/usr/share/mediatomb/js/playlists.js</playlist-script>
   <virtual-layout type='built-in'>
     <import-script>/usr/share/mediatomb/js/import.js</import-script>
     <dvd-script>/usr/share/mediatomb/js/import-dvd.js</dvd-script>
   </virtual-layout>
 </scripting>

And change it to this:

<scripting script-charset='UTF-8'>
   <common-script>/usr/share/mediatomb/js/common.js</common-script>
   <playlist-script>/usr/share/mediatomb/js/playlists.js</playlist-script>
   <virtual-layout type='js'>
     <import-script>/usr/share/mediatomb/js/import.js</import-script>
     <dvd-script>/usr/share/mediatomb/js/import-dvd.js</dvd-script>
   </virtual-layout>
 </scripting>

Note the change of virtual-layout type from built-in to js.

Import Script

There are dozens of different import options available, I prefer one similar to my file structure layout I have created on the server itself.

You’re going to need the import script locally so either download it through your browser or:

wget -O import-alver.js http://mediatomb.cc/dokuwiki/_media/scripting:import-alver.js

This should leave a complete copy in your current directory.

Since we copied the original import.js to a backup (you did, right?), we can move the new import script to where mediatomb expects to find it: sudo mv import-alver.js /usr/share/mediatomb/js/import.js and edit the video section to something that matches our file system layout.

There is one minor problem with this import file, the addCdsObject function comes with an extra variable that is incompatible with our mediatomb. We need to get rid of that. In whatever editor you’re using, replace-all of the following: “, UPNP_CLASS_CONTAINER”, “, UPNP_CLASS_CONTAINER_MUSIC_ALBUM”, and “, UPNP_CLASS_MUSIC” with nothing.

In the end, parts like this:

addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER);

Will look like this:

addCdsObject(obj, createContainerChain(chain));

Video Import

My video files are laid out like so:

/srv/video/
/srv/video/etc/
/srv/video/movies/
/srv/video/podcasts/
/srv/video/stand-up/
/srv/video/tv-complete/
/srv/video/tv-ongoing/

I’d like all the “movies” and “television” to each be in their own directories, and everything else under “video” so I’ll edit the import script and make some changes. Originally the addVideo function in the import.js file we just downloaded look like this:

function addVideo(obj)
{
    var chain, show, season;
    var location = obj.location.split('/');
    chain = new Array();

    if (location[2] == 'series')
    {
        chain.push('Series'); //genre name  (Series, Movies)
        chain.push(location[3]); //series name  (MySeries)
        chain.push(location[4]); //season (Series 1, 2, ...)
    }
    else if (location[2] == 'movies')
    {
        chain.push('Movies');
        chain.push(location[3]);
    }

    addCdsObject(obj, createContainerChain(chain));
}

I’m going to expand it into this:

function addVideo(obj)
{
    var chain, show, season;
    var location = obj.location.split('/');
    chain = new Array();
    if (location[3] == 'tv-ongoing'){
        chain.push('TV');
        chain.push(location[4]);
        if (location[6]) {
                chain.push(location[5]);
        }
    } else if (location[3] == 'tv-complete') {
        chain.push('TV');
        chain.push(location[4]);
        if (location[6]) {
                chain.push(location[5]);
        }
    } else if (location[3] == 'movies') {
        chain.push('Movies');
        chain.push(location[4]);
        if (location[6]) {
                chain.push(location[5]);
        }
    } else if (location[3] == 'podcasts') {
        chain.push('Podcasts');
        chain.push('Video');
        chain.push(location[4]);
    } else {
        chain.push('Video');
        chain.push(location[3]);
        if (location[5]) {
                chain.push(location[4]);
        }

    }
    addCdsObject(obj, createContainerChain(chain));
}

First, some notes: location[3] means the third directory, so for the folder /srv/video/tv-downloads/ the third directory would be tv-downloads, this is because we split the initial location for the file var location = obj.location.split('/'); (the same holds true for location[4] and location[5], they would be the fourth and fifth directory, respectively).

For each of the three conditional statement above we have some special conditions to follow, and a generic “catch-all” at the end. The first three are all very similar so I’m just going to explain one.

If the third directory for the video file we’re currently processing is “tv-ongoing”:

if (location[3] == 'tv-ongoing') {

add the fourth location under the “TV” chain:

    chain.push('TV');
    chain.push(location[4]);

if there is a sixth location (meaning there must be a fifth) also add the fifth location under the chain:

    if (location[6]) {
            chain.push(location[5]);
    }
}

This last bit is important, some folders are further divided into even more directories, this takes care of that, and adds them under the folder (if any) already specified in the file system. We can’t use location[5] in the conditional statement, because location[5] is the video file we might be currently processing, so we have to see if there is a sixth location.

The last option (after the final else) just handles everything else and adds it under the “video” root using similar layout as the previous example.

At the end of the three conditions and the catch-all we have this:

addCdsObject(obj, createContainerChain(chain));

Which adds the video file along with the chain we’ve been building to the database.

All of this might not make much sense now, however, it will turn files like this:

# a few movies
/srv/video/movies/American-Samoa/Big-Feet,-Big-Men.avi
/srv/video/movies/Fallout:-New-Vegas/Ultimate-Hacks.avi
/srv/video/movies/Bananafan/when-bananas-attack.avi

# some television
/srv/video/tv-ongoing/Gun-Smoke/01-01-the-truth.avi
/srv/video/tv-ongoing/Gun-Smoke/01-02-the-secret.avi

# more television
/srv/video/tv-complete/Gun-Smoke/09-01-the-hood.avi
/srv/video/tv-complete/Gun-Smoke/09-02-explains-a-banana.avi

# and some generic video
/srv/video/etc/favorite-food-group/head-cheese.avi

Into this:

/TV/Gun-Smoke/01-01-the-truth.avi
/TV/Gun-Smoke/01-02-the-secret.avi
/TV/Gun-Smoke/09-01-the-hood.avi
/TV/Gun-Smoke/09-02-explains-a-banana.avi

/Movies/American-Samoa/Big-Feet,-Big-Men.avi
/Movies/Fallout:-New-Vegas/Ultimate-Hacks.avi
/Movies/Bananafan/the-secret.avi

/Video/favorite-food-group/head-cheese.avi

Note how the separate files from tv-ongoing and tv-complete are now served together from one directory.

Restart mediatomb: sudo /etc/init.d/mediatomb restart and begin adding media.

Audio Import

I tend to follow the examples set forth in the import script we’ve already downloaded. I do, however make one change: I don’t like other audio files messing up the layout of my actual music, so I add a conditional statement. Just below this line:

function addAudio(obj) {
		

I add this:

    var location = obj.location.split('/');
    if (location[3] == 'music') {

So it looks like this:

function addAudio(obj) {
    var location = obj.location.split('/');
    if (location[3] == 'music') {

Then, just at the end of the addAudio function where it looks like this:

    chain = new Array('Music', 'Genres', genre, artist, album);
    addCdsObject(obj, createContainerChain(chain));
}

I make it look like this:

    chain = new Array('Music', 'Genres', genre, artist, album);
    addCdsObject(obj, createContainerChain(chain));
} else if (location[3] == 'podcasts') {
    chain = new Array();
    chain.push('Podcasts');
    chain.push('Audio');
    chain.push(location[4]);
    addCdsObject(obj, createContainerChain(chain));
}

This gently moves audio podcasts out my my Music chain, and into the Podcast chain, specifically under Audio, and then the folder that the audio file lives in.

Post-Update Warnings

Whenever mediatomb is updated our configuration and import file are overwritten, which is unfortunate. You might wonder why we don’t change the name of those two files so we never have to worry about it. I’ve had several problems with mediatomb and different file-names in the past, so I merely keep another copy, and replace after an update.

You can handle it however you wish.