howtos

Example of how to put RDFa into an HTML list

I'm not going to try to explain RDF and/or RDFa here, but thought any poor suckers looking for RDFa examples might benefit from me posting what I finally worked out, with help from my colleague Rob. Namely, how to annotate an HTML ordered list (<ol>) with RDFa attributes; and how to put RDFa attributes onto form elements.

Here's the HTML page with RDFa embedded in it. What I'm representing here is a sequence of collections, and the individual collections within it:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Collections</title>
  </head>
  <body>
    <h1>Collections</h1>
    <form method="post" action="http://receptacular.org/collections">
      <ol xmlns="http://www.w3.org/1999/xhtml" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xsd="http://www.w3.org/2001/XMLSchema#" xmlns:rec="http://receptacular.org/schema#" typeof="rdf:Seq" about="http://receptacular.org/collections">
        <li rel="rdf:_1" resource="http://receptacular.org/collections/1">
          <span style="display:none;" rel="rdf:type" resource="http://receptacular.org/schema#Collection"></span>
          <div class="collection-label" property="rdfs:label">Vague Collection</div>
          <input type="checkbox" id="collections-1-hidden" property="rec:hidden" datatype="xsd:boolean" content="false"/>
          <label for="collections-1-hidden">hidden</label>
          <input type="checkbox" id="collections-1-defaultSearch" property="rec:defaultSearch" datatype="xsd:boolean" content="false"/>
          <label for="collections-1-defaultSearch">use for searches</label>
        </li>
        <li rel="rdf:_2" resource="http://receptacular.org/collections/2">
          <span style="display:none;" rel="rdf:type" resource="http://receptacular.org/schema#Collection"></span>
          <div class="collection-label" property="rdfs:label">Archive Collection</div>
          <input type="checkbox" id="collections-2-hidden" property="rec:hidden" datatype="xsd:boolean" content="false"/>
          <label for="collections-2-hidden">hidden</label>
          <input type="checkbox" id="collections-2-defaultSearch" property="rec:defaultSearch" datatype="xsd:boolean" content="false"/>
          <label for="collections-2-defaultSearch">use for searches</label>
        </li>
        <li rel="rdf:_3" resource="http://receptacular.org/collections/3">
          <span style="display:none;" rel="rdf:type" resource="http://receptacular.org/schema#Collection"></span>
          <div class="collection-label" property="rdfs:label">Main Collection</div>
          <input type="checkbox" id="collections-3-hidden" property="rec:hidden" datatype="xsd:boolean" content="true" checked="checked"/>
          <label for="collections-3-hidden">hidden</label>
          <input type="checkbox" id="collections-3-defaultSearch" property="rec:defaultSearch" datatype="xsd:boolean" content="true" checked="checked"/>
          <label for="collections-3-defaultSearch">use for searches</label>
        </li>
      </ol>
      <p>
        <input type="button" value="Save" id="save-collections"/>
      </p>
    </form>
  </body>
</html>

Available online here: http://receptacular.org/collections

Things of note:

  • The doctype declaration. This is the W3C sanctioned doctype for XHTML+RDFa pages. By the way, the W3C validator will correctly validate this page, but standard XHTML validators don't (e.g. like "this one"http://nutrun.com/weblog/xhtmlvalidator-validate-xhtml-in-java/:). That's another story...
  • Namespace declarations on the <ol> element wrapping the list items. This is what causes standard XHTML validation approaches to fail.
  • The <ol> element is defined with typeof="rdf:Seq" and about="http://receptacular.org/collections". This sets it up as the RDF Seq resource.
  • The <li> elements inside the <ol> are Seq items, within the wrapping Seq resource. Each is each defined as a resource using the resource attribute. They are linked back to the enclosing <ol> element using the rel attribute on each. Note that the value for the rel attribute is an rdf Seq number, which orders the items within the enclosing Seq resource.
  • The RDF type of each Seq item is set using a hidden <span> element. Note that these elements have no text in them, but have opening and closing tags. If you just use a self-closing start tag for this element, the HTML doesn't display property.
  • The <span> elements use the rel attribute to mark their RDF type relationship to the outer list item; and the resource attribute to specify the location of the resource representing their type.
  • Each Seq item has an enclosed <div> which represents its rdfs:label property. Note that the property RDFa attribute is used to specify which property of the enclosing resource is being defined. Also note that the value of the property is inlined between the start and end tags of the <div>.
  • The two checkboxes define two more properties for each Seq resource: rec:hidden and rec:defaultSearch. (The semantics of the properties aren't discussed here, as I'm concentrating on syntax.) Each is defined on a standard XHTML <input> element: the relationship to the enclosing Seq item is defined with the property attribute; the value of the property is defined using the content attribute; and the data type of the literal value is defined via the datatype attribute. Any of the standard XML datatypes could be used here, or other types from other schemas.
  • When working with form elements which represent property values for RDF resources, you may need to change the content attribute in response to UI changes. (In the application from which this example was extracted, we use JQuery to respond to changes in the check box which set the content attribute.)

To see the RDF which can be extracted from this page, you can use the W3C's RDFa Distiller. Here's the resulting RDF:

<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF
  xmlns:dist="http://www.w3.org/2007/08/pyRdfa/distiller#"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
  xmlns:rec="http://receptacular.org/schema#"
  xmlns:xhv="http://www.w3.org/1999/xhtml/vocab#"
  xmlns:xml="http://www.w3.org/XML/1998/namespace"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
>
  <rdf:Seq rdf:about="http://receptacular.org/collections">
    <rdf:_1>
      <rec:Collection rdf:about="http://receptacular.org/collections/1">
        <rec:hidden rdf:datatype="http://www.w3.org/2001/XMLSchema#boolean">false</rec:hidden>
        <rec:defaultSearch rdf:datatype="http://www.w3.org/2001/XMLSchema#boolean">false</rec:defaultSearch>
        <rdfs:label>Vague Collection</rdfs:label>
      </rec:Collection>
    </rdf:_1>
    <rdf:_2>
      <rec:Collection rdf:about="http://receptacular.org/collections/2">
        <rec:hidden rdf:datatype="http://www.w3.org/2001/XMLSchema#boolean">false</rec:hidden>
        <rec:defaultSearch rdf:datatype="http://www.w3.org/2001/XMLSchema#boolean">false</rec:defaultSearch>
        <rdfs:label>Archive Collection</rdfs:label>
      </rec:Collection>
    </rdf:_2>
    <rdf:_3>
      <rec:Collection rdf:about="http://receptacular.org/collections/3">
        <rec:hidden rdf:datatype="http://www.w3.org/2001/XMLSchema#boolean">true</rec:hidden>
        <rec:defaultSearch rdf:datatype="http://www.w3.org/2001/XMLSchema#boolean">true</rec:defaultSearch>
        <rdfs:label>Main Collection</rdfs:label>
      </rec:Collection>
    </rdf:_3>
  </rdf:Seq>
</rdf:RDF>

Saving changes to an RDFa-enabled form like this is another challenge, for which we used rdfquery, and RDF library for JQuery. (I recommend you use the latest svn HEAD version of this library, as older versions have a bug where they ignore RDFa elements nested inside elements without RDFa attributes.) Maybe I'll get round to that another time.

Script to copy random mp3s from a directory to an mp3 player

This is a Ruby script which randomly copies mp3 files from one directory to an mp3 player. I wrote it so I could easily fill up my mp3 player from the 9000 odd mp3s I have on a different external drive.

To run it, you'll need the sys-filesystem gem (see http://rubyforge.org/projects/sysutils):

$ gem install sys-filesystem

Next, edit these variables in the script (near the top):
* source_dir to the directory containing the mp3s you want to select from
* dest_dir to the path for the directory on your mp3 player you want to copy to

Be a bit careful, as this will attempt to fill the dest_dir you specify with mp3 files from source_dir. You might end up filling the wrong disk up.

Then just run it with ruby from the command line:

$ ruby mp3s_random.rb

Note that it won't delete anything from the destination drive, and will attempt to fill all the space available. Also note that it doesn't keep trying mp3s until it finds one which will fit the last remaining space: once it tries to copy a file which won't fit, it stops. You can always run it again to see whether the next run finds a file small enough to fit.

I've only tested it on Linux, but, who knows, it might work on Windows too. (No operating-system specific commands are used in the script, as it uses Ruby for all file operations.)

The code is below, but I've attached it as well.

require 'rubygems'
require 'sys/filesystem'
require 'ftools'

source_dir = '/media/disk/music'
dest_dir = '/media/disk-1/music'

files = Dir[File.join(source_dir, '/**/*.mp3')]
num_files = files.size

stat = Sys::Filesystem.stat(dest_dir)

disk_free_space_kb = (stat.blocks_free * stat.fragment_size).to_kb

files_selected = []

while disk_free_space_kb > 0 and num_files > 0 do
  # choose an mp3
  file_num_to_copy = rand(num_files - 1) + 1
  file_path = files.delete_at(file_num_to_copy)

  num_files = num_files - 1

  # work out how big file is
  file_size_kb = File.stat(file_path).size.to_kb

  # subtract from free space
  if (disk_free_space_kb - file_size_kb) > 0
    files_selected << file_path
    disk_free_space_kb = disk_free_space_kb - file_size_kb
  else
    break
  end
end

files_selected.each do |f|
  copy_to_path = File.join(dest_dir, File.basename(f))
  puts "Copying #{f} to device"
  File.copy(f, copy_to_path)
end

Decoding FLV files with ffmpeg

I'm using Ubuntu Intrepid Ibex, but the ffmpeg distribution it comes with doesn't support recent FLV file encodings (like some videos from YouTube). You get an error like this when you try to do anything with them:

[flv @ 0xb800e4c8]Unsupported video codec (7)

My solution was to checkout ffmpeg from its Subversion repository and compile it myself:

$ svn checkout svn://svn.ffmpeg.org/ffmpeg/trunk ffmpeg-svn
$ cd ffmpeg-svn
$ ./configure --prefix=~/apps/ffmpeg-svn --enable-libmp3lame
$ make install

To do the compile, you'll probably need build-essential, as well as libmp3lame-dev, and the *-dev versions of any other codecs you want to use.

Use the resulting binary to do the conversion:

$ ~/apps/ffmpeg-svn/bin/ffmpeg -i infile.flv outfile.mpg

It turns out this version does support those recent FLV files, happily.

Describing (finding) subjects which don't have a particular predicate in SPARQL

If you want to do something like a SQL NOT in SPARQL, here's what the query looks like:

PREFIX rs: <http://schemas.talis.com/2006/recordstore/schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

DESCRIBE ?tenancy {
  ?tenancy rdf:type rs:Tenancy .
  OPTIONAL { ?tenancy rs:platformStoreUri ?o } .
  FILTER ( !bound(?o) )
}

Here I'm looking for subjects with rdf type of http://schemas.talis.com/2006/recordstore/schema#Tenancy, which don't have a http://schemas.talis.com/2006/recordstore/schema#platformStoreUri predicate. The important bit is that you make the predicate which could potentially not be "set" OPTIONAL; and add a FILTER which only includes subjects where the predicate is bound to a value. This effectively screens out any subjects where the predicate has not been added to the subject. This pattern is basically Negation as Failure (according to the SPARQL recommendation), which derives from logic programming. Feels a bit like being back at university.

Installing Windows on the second hard disk of a Linux machine

I recently upgraded the hardware of my old desktop PC, with the aim of providing the house with a new-ish Linux machine for watching movies and using the internet, and a Windows machine for writing music and playing (old) games. My plan was to use two hard disks: one for Linux, another for Windows, and choose which to use at boot time.

Normal procedure is to install Windows first, then install Linux into a spare partition on the same hard drive (Windows tends to overwrite any disk you put it on). But it's easier to get a Linux machine up and running, see what hardware you've got, and get a decent system without needing to go and find loads of old drivers. So I decided to install Linux first. I plugged in a drive for it as the Primary IDE drive, and installed Ubuntu Linux onto it.

Then, I unplugged the Linux drive, plugged the other drive in, and installed Windows 2000 onto the second drive (just to make sure Windows couldn't overwrite Linux). Got that working too.

Then I plugged the Linux drive in, as the first drive on the IDE cable; and the Windows disk as the second.

The trick then is to get grub (the Linux bootloader I'm using) to present you with both disks as options as boot time. There's a sample configuration in /boot/grub/menu.lst, but that didn't work for me: it looked like it was working, then just hung. I tried a couple of things, but nothing which worked.

Finally, I found this blog entry and used the configuration there. The trick is to make Windows think it's installed on the first disk on the IDE cable. I added this to the bottom of menu.lst:

title Windows 2000
rootnoverify (hd1,0)
map (hd0) (hd1)
map (hd1) (hd0)
chainloader +1

which does the trick! Now I get a working Windows 2000 option in my grub boot menu.

Creating a self-signed SSL certificate for Apache on Linux

(This is extracted from my Apache course materials, but it's a useful howto in its own right.)

To generate a self-signed SSL certificate, you will need openssl installed first.

Then follow these steps:

  1. Generate the server's private key; we'll use a 1024-bit key using the RSA algorithm:
    openssl genrsa -out server.key 1024
  2. Generate a certificate-signing request:
    openssl req -new -key server.key -out server.csr
  3. Fill in the required information at the prompts:
       Country Name (2 letter code) [GB]:GB
       State or Province Name (full name) []:.
       Locality Name (eg, city) [Newbury]:Birmingham
       Organization Name (eg, company) [My Company Ltd]:Talis
       Organizational Unit Name (eg, section) []:Library Products
       Common Name (eg, your name or your server's hostname) []:prism.talis.com
       Email Address []:.
    
       Please enter the following 'extra' attributes to be sent with your certificate request
    
       A challenge password []:.
       An optional company name []:.
    
    The really important one is the Common Name: this must match the domain name which will serve the SSL site; otherwise connecting clients will get a prompt about a mismatch between the certificate's host name and the actual host name of the server.

    Note that we left the password blank. If we don't do this, Apache will prompt you for the certificate password each time you start the server, which is a pain in the arse.
  4. Create a self-signed certificate from the certificate-signing request (.csr file):
    openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt
  5. rm server.csr (you don't need it any more)
  6. Put the .crt and .key files into Apache's SSL directory and configure Apache to use them

If I get round to it I'll do another entry explaining how to make Apache use them.

Dealing with self-signed SSL certificates when running Selenium server with Firefox

Selenium is a decent tool for testing web UIs, with good integration with a variety of languages. We use it on Talis Prism for testing the UI, running a Selenium server instance then firing Ruby rspec tests and an older HTML suite at it. Here's the part of the Ant build script which runs the HTML suite using Selenium :

<target name="prism-selenium-tests" description="Run the old Prism Selenium tests">
  <echo message="Running old Selenium tests against Prism" />
  <java jar="test/dependencies/Selenium/selenium-server.jar" fork="true" maxmemory="1024m">
    <arg line="-debug -timeout 500 -htmlSuite '*chrome ${firefox.bin}' http://${prism.host} \
       test/selenium/testSuite.html doc/seleniumResults.html" />
  </java>
</target>

where the variables we interpose are:

${firefox.bin} = path to the Firefox binary to use
${prism.host} = HTTP host to run the tests against

This works without a hitch if you're not using HTTPS; but as soon as your tests redirect to an HTTPS URL on the same host (we serve parts of Prism over SSL), where your SSL certificate is self-signed, things go wrong. As Selenium effectively runs Firefox with a new profile every time, you potentially lose any certificate exceptions you might accept.

One technique we were using was to create a custom profile; run Firefox using that profile; browse to the HTTPS URL and accept the exception into that profile; then close the profile.

This kind of worked, but we still got odd popups from Firefox about new extensions being installed. Just annoying.

I think I've now worked out the solution, which was largely based on http://kapanka.com/2008/12/selenium-rc-firefox-and-the-self-signed-ssl-c.... It's a bit of a pain in the arse, but it does seem to work. Here goes.

  1. Close down any running Firefox instances.
  2. Start Firefox (the one you're going to run your tests with) with the profile manager: firefox -ProfileManager
  3. Create a new profile. You'll be prompted to choose a directory for the profile. Put it somewhere inside the project where you're writing the tests.
  4. Select the profile and run Firefox using it.
  5. Browse to the HTTPS URL (with self-signed certificate) you're going to be testing against.
  6. Accept the self-signed certificate when prompted. This creates an exception for it in the profile.
  7. Close the browser.
  8. Go to the Firefox profile directory.
  9. Delete everything in the directory except for the cert_override.txt and cert8.db files.
  10. When you run your Selenium server (like in my Ant example above), pass a -firefoxProfileTemplate /path/to/profile/dir argument to it. This tells Selenium to use your partial profile (with certificate exceptions) as a basis for minting its new profile. So you get the certificate exceptions, but without any of the other clutter you would get if you used a whole profile.

The Ant task above, with this option, looks like this:

<target name="prism-selenium-tests" description="Run the old Prism Selenium tests">
  <echo message="Running old Selenium tests against Prism" />
  <java jar="test/dependencies/Selenium/selenium-server.jar" fork="true" maxmemory="1024m">
    <arg line="-debug -timeout 500 -firefoxProfileTemplate test/firefoxProfile \
       -htmlSuite '*chrome ${firefox.bin}' http://${prism.host} test/selenium/testSuite.html doc/seleniumResults.html" />
  </java>
</target>

Outside of Ant, the command might look something like:

java -jar test/dependencies/Selenium/selenium-server.jar -firefoxProfileTemplate /path/to/profile \
-htmlSuite '*chrome firefox-bin' http://host.com testSuite.html seleniumResults.html

Works for me.

Skype on Ubuntu Intrepid Ibex 8.10

I upgraded my laptop just before Christmas, but unfortunately couldn't get Skype working easily.

First off, I tried the packages for Ubuntu provided by Skype, but I couldn't get them to work. Instead, I used the Medibuntu Skype package. To use these, you just add a couple of repositories to your apt sources: see this page for details.

These worked, kind of: Skype started, but the audio capture didn't work. I found this article, which suggests a fix, by turning off pulseaudio (the default, poorly-configured sound server for Intrepid).

But this didn't seem to completely solve my issues, as Skype kept hanging when you tried to close it down.

So, instead, I followed these longer but more comprehensive instructions, which leave pulseaudio turned on, but fix its configuration. They seem to have done the trick.

Installing Xdebug for PHP 5 on Ubuntu "Feisty Fawn"

Xdebug is a PHP debugger with nice Eclipse integration. Here are some instructions for installing it (assuming you already have Apache 2 and PHP 5).

This article explains in more detail, but isn't Ubuntu-specific. It does detail Eclipse configuration for Xdebug in detail, though.

You need to be root to do the installation.

First off, install Xdebug. This isn't packaged for Ubuntu, so you need to do it with PECL. So install PECL if you don't have it:

apt-get install pecl

Use PECL to install Xdebug:

pecl install xdebug

Configure PHP 5 to use Xdebug by adding these lines to /etc/php5/apache2/php.ini (somewhere near where the other extension= lines are):

zend_extension=/usr/lib/php5/20060613+lfs/xdebug.so

[xdebug]
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_port=9000
xdebug.remote_host=127.0.0.1
xdebug.remote_log=/var/log/apache2/xdebug_remote.log

Note you need to use zend_extension= to load the extension, and you should use the absolute path to the module (.so file) to do this. Otherwise it fails.

Check using PHP info, e.g. add a file called phpinfo.php to your web root:

<?php phpinfo(); ?>

Then call it in your browser. Check that there is an Xdebug section displayed.

That's Xdebug installed. See the article linked at the start of this entry if you want to integrate with Eclipse.

Doing all sorts of burning, ripping and encoding of video and DVDs and audio (on Linux)

Using Linux every day means that I often grapple with how to re-encode proprietary formats so that I can watch them on the computer of my choice. I also do some DVD ripping and creating new DVDs of home movies etc., for which the Linux command line tools work very nicely (more quickly, more consistently and in a more stable fashion than some of the GUIs).

So I've gathered a whole load of tips on encoding, ripping, burning, culled from dozens of forums, websites, manpages etc.. This, then, is the current state of my understanding on this topic, and hopefully distills many hours of pain into an easily-digestible format. It's not very well organised, but hopefully useful. I should mention that this stuff works on Ubuntu, but your mileage may vary. Here goes.

A note on tools

All of the tools I use are easily installable on Ubuntu, either from official repositories or universe/multiverse. You will also need to install the proprietary codecs if you want to work with them. Here's what I tend to use:

  • vlc media player
  • mplayer media player
  • ffmpeg format transformer
  • mencoder
  • dvgrab
  • dvdauthor
  • dvdbackup
  • growisofs
  • mkisofs
  • sox
  • lame
  • cdrecord

Burning an ISO onto a DVD/CD

To work out where your CD/DVD device is:

$ cdrecord -scanbus
scsibus1:
        1,0,0   100) 'HL-DT-ST' 'DVD+-RW GSA-T11N' 'A103' Removable CD-ROM
        1,1,0   101) *
        1,2,0   102) *
        1,3,0   103) *
        1,4,0   104) *
        1,5,0   105) *
        1,6,0   106) *
        1,7,0   107) *

What you're looking for is an entry with something other than a * in it; then get the content of the first column, which is the device ID (here, it's 1,0,0).

Then:

cdrecord -v -dao dev=1,0,0 image.iso

setting dev= to the ID you found above, and where image.iso is the path to your ISO image file.

Getting the audio out of a YouTube video into an mp3 file

First off, download the FLV version of the video. This is the tricky bit, but here's how to find it:

  1. Go to the YouTube page for the video
  2. Copy the content of the v parameter in the querystring (the video ID)
  3. View the source of the web page
  4. Search for "f": in the source; following this will be a long text string (the t parameter), e.g. "OEgsToPDskLJFcLZay_H2RO2hijVCxkP". This is some kind of secret token you'll need to do the download.
  5. Construct the URL as follows:
http://www.youtube.com/get_video?video_id=<video ID>&t=<t parameter>

Use your favourite browser or downloader to fetch the file (FLV format).

My new technique for getting the mp3:

ffmpeg -vn -i youtubevideo.flv youtubevideo.mp3

You'll need a recent ffmpeg for some YouTube videos, and will also need mp3 support compiled in to do this conversion.

My old technique for getting the mp3:

Once you've downloaded it, play it through mplayer, resampling the audio at 44.1KHz:

mplayer -vo null -vc null -ao pcm:file=out.wav -af resample=44100:0:0 youtubevideo.flv

Then, use lame to encode the wav file to mp3:

lame -h -V0 out.wav out.mp3

This does a reasonable quality, variable bit-rate mp3.

There are a couple of services which do this (e.g. YouTubeHack) and a command line script, but I couldn't get the services to work, and couldn't be bothered with the command line script.

mp4 or mov to mpg

Use mencoder for this. mp4 version:

mencoder in.mp4 -ovc lavc -oac lavc -o out.mpg

mov version is practically the same:

mencoder in.mov -ovc lavc -oac lavc -o out.mpg

Ripping from a dv camera with dvgrab

dvgrab --autosplit --timestamp --format jpeg

(The camera should be detected automatically, and I think this waits until it detects some input before the capture starts. I use a firewire cable to connect from the camera to the computer.) The files get named after timestamps coming from the film.

Encoding from .avi to .mpg

Use:

ffmpeg -i infile.avi outfile.mpg

(though this produces quite low quality output)

This produces better quality (bitrate = 800):

ffmpeg -i infile.avi -vcodec mpeg2video -acodec mp2 -b 800 outfile.mpeg

Encoding from .avi to .mpg suitable for DVD burning

ffmpeg -i finalmovie.avi -y -target pal-dvd -sameq -aspect 16:9 finalmovie.mpg

If you're in the US, changed pal-dvd to ntsc-dvd.

Ripping DVDs to hard disk

(See http://www.bunkus.org/dvdripping4linux/single/index.html for lots of good tips)

May need dvdcss decoder to be installed:

sudo /usr/share/doc/libdvdread3/examples/install-css.sh

Use dvdbackup to rip a DVD to hard disk.
See http://dvd-create.sourceforge.net/dvdbackup-readme.html for full instructions

# Get info. about DVD
dvdbackup -i /dev/cdrom -I

# Rip whole DVD
dvdbackup -M -i/dev/cdrom -o /media/usbdisk/dvdripping

# Rip main feature
dvdbackup -F -i /dev/cdrom -o /media/usbdisk/dvdripping

# Rip title set (in this case, title set 2)
dvdbackup -T 2 -i /dev/cdrom -o /media/usbdisk/dvdripping

# Rip title (here, rip title 1)
dvdbackup -t 1 -i /dev/cdrom -o /media/usbdisk/dvdripping

Direct DVD copying

This effectively copies the DVD's iso image to hard disk:

dd if=/dev/cdrom of=file.iso bs=2048

If the disk is encrypted, this might fail. In this case, it might be worth running this first:

dvdbackup -I -i /dev/cdrom

Then try dd again.

See http://gentoo-wiki.com/HOWTO_Backup_a_DVD#dd for more details

Note that this produces a mountable DVD image. However, it does not remove encryption, so you would still need to rip to individual VOBs using dvdbackup to get rid of that. However, it is possible to mount the iso and play it as if it were a DVD (see later): vlc is good for this.

Playing a partially ripped DVD

If you've ripped some of the content of a DVD (e.g. using dvdauthor -i /dev/cdrom -F), you can play the partial rip with:

mplayer dvd:// -dvd-device <ripped_dvd_directory>

(vlc might also be able to do this)

Encoding audio out of a VOB file (note that this drops the video altogether)

mplayer -vo null -vc null -ao pcm:file=outfile.wav infile.VOB

You could probably use ffmpeg for this, too.

Creating a DVD using dvdauthor when you don't want the whole disc

If you just have the main feature (a set of .VOB files) and you want to create a playable DVD from them.

Create a dvd.xml file in the top level directory of the ripped DVD (e.g. in VIDEO_TS)

<dvdauthor>
  <vmgm />
    <titleset>
      <titles>
        <pgc>
          <vob file="VTS_01_1.VOB" />
          <vob file="VTS_01_2.VOB" />
          <vob file="VTS_01_3.VOB" />
          <vob file="VTS_01_4.VOB" />
          <vob file="VTS_01_5.VOB" />
        </pgc>
      </titles>
    </titleset>
</dvdauthor>

(Adding another element for each VOB which you want included in your "movie". Note that these can equally well be your own mpg files.) You can also add titles etc.: see the man page for dvdauthor for more details. This works fine for me, though.

Then run it with:

dvdauthor -o <output directory for DVD structure> -x dvd.xml

Burning complete DVD structure to a new DVD

See http://www.linux.com/articles/53702

(I think you might need to have used dvdbackup -M (complete rip) for this to work, or have a DVD structure created using dvdauthor (see above))

growisofs -dvd-compat -Z /dev/cdrom -dvd-video <ripped dvd structure>

Creating an iso from a ripped DVD structure

If you've ripped the structure of a DVD (e.g. using dvdbackup) or created your own DVD structure (e.g. using dvdauthor), you can turn it into a single iso file with:

mkisofs -dvd-video <ripped dvd directory> | dd of=file.iso obs=32k seek=0

Mounting an iso filesystem so you can read it

mkdir mountpoint
sudo mount -o loop file.iso mountpoint

Once mounted, you can play the mounted iso (including its menu system) using vlc. For example, if we mounted it on the directory "mountpoint" we could do:

vlc dvd:///path/to/mountpoint

Encode VOB to mpg

If you ripped a VOB off a DVD but you want a smaller mpg:

ffmpeg -i VTS_01_1.VOB -vcodec mpeg2video -acodec mp2 -b 1000 sleeper1.mpg

Ripping RealPlayer streams

See https://help.ubuntu.com/community/HowToRipRealaudioStreamsToMp3 for full instructions

Short version:

vsound --timing --dspout --file=myfilename.wav realplay http://url.to.rip

Ruby script for converting from m4a (iTunes format?) to mp3

This is a shell script for converting files from m4a to mp3. It uses mplayer and lame behind the scenes. sox is supposed to do this, but I can never work out how to install proprietary codecs for it. This doesn't retain tags, unfortunately. Sneetchalizer will probably also work.

#!/opt/lampp/bin/ruby
# only works if the script is in the directory with the m4a files
prefix = "new_file_prefix"
Dir['*.m4a'].each do |f|
  new_filename = prefix + File.basename(f).gsub(' ', '_').slice(3..-5).downcase
  wav = new_filename + ".wav"
  mp3 = new_filename + ".mp3"
  `mplayer -ao pcm:file='#{wav}' '#{f}'`
  `lame -h -b192 #{wav} #{mp3}`
  `rm #{wav}`
end

Ruby script for converting from ogg to mp3

Uses ogg123. This script loses all the tags, though. Sneetchalizer would do this, too.

#!/opt/lampp/bin/ruby

filename = ARGV[0]

if filename.nil? or !(/\.ogg$/ =~ filename)
  puts "I don't think that's an ogg file, mister"
  exit
end

base_filename = filename.chomp(".ogg")
mp3_filename = base_filename + ".mp3"

`ogg123 -d au -f - #{filename} | lame - #{mp3_filename}`

mp3 to ogg

Bit basic, this, but you get the idea:

mpg321 -s input.mp3 | oggenc -r -a "artist" -t "title" -b 100 -M 140 -o output.ogg -

ogg to wav

sox is OK for this, as neither codec is proprietary:

sox input.ogg output.wav
Syndicate content