Monday, April 18, 2011

So my buddy over at Forshee Media was asking me the other day if I could build him a DVD duplicator on the cheap. I said “Challenge Accepted”. Here's how I did it.

The Hardware

Being a guy that works in the IT field, I get a lot of junk or old systems donated to me. I had plenty of parts sitting around to build a decently running, purpose built appliance like this, but I wouldn't want to use systems with their specs for a main desktop. Here are the specs:

  • Pentium 4 processor
  • 512MB PC2-3200
  • 1 – 80GB PATA Drive for the OS
  • Motherboard with 4 SATA ports
  • 2 PATA connectors
  • Case with at least 4-5.25” drive bays

Sounds pretty simple right? I also had a few DVD burners sitting around that I could use to test the software. I didn't have the 4 burners that he wanted but the software would scale.

The Software

I installed Ubuntu 10.10 Server Edition on it because it takes up very few resources. This device will have nothing but a power cord and a network cable hooked to it. As such, it will be remotely controlled via ssh.

The network card has everything statically assigned. I got some of my buddy's network specs ahead of time. How this can be accomplished is edit /etc/network/interfaces and here is what I added to his configuration:

iface eth0 inet static
address 192.168.1.200
netmask 255.255.255.0
gateway 192.168.1.1

Pretty simple. With an “apt-get install ssh”, I unhooked all of the peripherals and ran this thing like the headless drone it is supposed to be.

Up next was finding out what DVD drives are being recognized. This is important as the dev assignments are statically coded into the coming scripts. To find out what drives are available “udisks --enumerate | grep sr”. Normally optical drives are specified with an sr#. Your distro might vary.

The Code

Now we're getting to the good part. The meat and potatoes of this operation. Here is a script that works for me with 4 drives:

#!/bin/bash

dvd1=/dev/sr0
dvd2=/dev/sr1
dvd3=/dev/sr2
dvd4=/dev/sr3

dvd_prep(){
    local dvd_to_load=$1
    local state=$2
    dvd_load=0
    sleep 2
    while [ $dvd_load -eq 0 ]
    do
        dvd_load=`udisks --show-info $dvd_to_load | grep -c "blank: *$state"`
    done
}

echo "Load DVD into top tray"
eject $dvd1
dvd_prep $dvd1 0
echo "Copying DVD to image"
dd if=$dvd1 of=dvdimage.iso bs=512
eject $dvd1

echo "How many copies?"
read copies
count=1
while [ $count -le $copies ]
do
    remaining=0
    if [ $copies -gt 1 ]
    then
        remaining=$((copies-count))
    fi

    if [ $copies -eq 1 -o $remaining -eq 0 ]
    then
        dvd_prep $dvd1 1
        echo "Number $count"
        eject $dvd1
        growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd1=dvdimage.iso > duplicator_log 
        eject $dvd1
        let "count+=1"

    elif [ $copies -eq 2 -o $remaining -eq 1 ]
        eject $dvd1
        eject $dvd2
       
        dvd_prep $dvd1 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd2 1
        echo "Number $count"
        let "count+=1"
        growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd1=dvdimage.iso  > duplicator_log  && eject $dvd1 & growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd2=dvdimage.iso  > duplicator_log && eject $dvd2 

    elif [ $copies -eq 3 -o $remaining -eq 2 ]
        eject $dvd1
        eject $dvd2
        eject $dvd3
       
        dvd_prep $dvd1 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd2 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd3 1
        echo "Number $count"
        let "count+=1"

        growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd1=dvdimage.iso  > duplicator_log  && eject $dvd1 & growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd2=dvdimage.iso  > duplicator_log && eject $dvd3 & growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd3=dvdimage.iso  > duplicator_log && eject $dvd3    
    else
        eject $dvd1
        eject $dvd2
        eject $dvd3
        eject $dvd4
       
        dvd_prep $dvd1 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd2 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd3 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd4 1
        echo "Number $count"
        let "count+=1"

        growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd1=dvdimage.iso  > duplicator_log  && eject $dvd1 & growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd2=dvdimage.iso  > duplicator_log && eject $dvd3 & growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd3=dvdimage.iso  > duplicator_log && eject $dvd3  & growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd4=dvdimage.iso  > duplicator_log && eject $dvd4 
    fi
done
echo "Done"
rm dvdimage.iso


All This does is copy DVDs. If it's worth doing, it's worth doing overkill. That being said...

LightScribe

Since the drives I bought for this project are LightScribe compatible, I decided to write a bit more in this script in order to turn this not only into a DVD toaster, but also make mass LightScribe operations possible. Doing more than, say, 5 of the same LS label is tedious.

Get this label here
I found that you need to have the LightScribe System software installed as well as the Lacie LS Utilities (because they have a scriptable CLI implementation). It is a bit of a process to get this working, but worth it.

How this works is when the DVD is done being written, the user is prompted to turn the DVD over to etch a bitmap label on the top. The LightScribe bits of this code are activated when the script is fed an argument of an image name without an extension (ex. "./duplicator label" not "./duplicator label.bmp")

Le Code in red is what was changed from the previous code:


#!/bin/bash

LS=$1
dvd1=/dev/sr0
dvd2=/dev/sr1
dvd3=/dev/sr2
dvd4=/dev/sr3

dvd_prep(){
    local dvd_to_load=$1
    local state=$2
    dvd_load=0
    sleep 2
    while [ $dvd_load -eq 0 ]
    do
        dvd_load=`udisks --show-info $dvd_to_load | grep -c "blank: *$state"`
    done
}

ls_prep(){
    local dvd_to_load=$1
    dvd_load=0
    sleep 2
    while [ $dvd_load -eq 0 ]
    do
        dvd_load=`4L-cli mediainfo $dvd_to_load | grep Oriented | cut -d' ' -f4`
    done
}


echo "Load DVD into top tray"
eject $dvd1
dvd_prep $dvd1 0
echo "Copying DVD to image"
dd if=$dvd1 of=dvdimage.iso bs=512
eject $dvd1

echo "How many copies?"
read copies
count=1
while [ $count -le $copies ]
do
    remaining=0
    if [ $copies -gt 1 ]
    then
        remaining=$((copies-count))
    fi

    if [ $copies -eq 1 -o $remaining -eq 0 ]
    then
        dvd_prep $dvd1 1
        echo "Number $count"
        eject $dvd1
        growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd1=dvdimage.iso > duplicator_log

    if [ $LS ]
    then    
        eject $dvd1
        echo "Flip the DVD over and close the drive tray."
        ls_prep $dvd1
        4L-cli print $dvd1 labels/$LS.bmp
    fi

        eject $dvd1
        let "count+=1"

    elif [ $copies -eq 2 -o $remaining -eq 1 ]
        eject $dvd1
        eject $dvd2
     
        dvd_prep $dvd1 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd2 1
        echo "Number $count"
        let "count+=1"
        growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd1=dvdimage.iso  > duplicator_log  && eject $dvd1 &
    growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd2=dvdimage.iso  > duplicator_log && eject $dvd2
  
if [ $LS ]
    then    
        eject $dvd1
        eject $dvd2
        echo "Flip the DVDs over and close the drive trays."
        
        ls_prep $dvd1
        ls_prep $dvd2

        4L-cli print $dvd1 labels/$LS.bmp &
        4L-cli print $dvd2 labels/$LS.bmp
    fi

    elif [ $copies -eq 3 -o $remaining -eq 2 ]
        eject $dvd1
        eject $dvd2
        eject $dvd3
     
        dvd_prep $dvd1 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd2 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd3 1
        echo "Number $count"
        let "count+=1"

        growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd1=dvdimage.iso  > duplicator_log  && eject $dvd1 &
    growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd2=dvdimage.iso  > duplicator_log && eject $dvd3 &
    growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd3=dvdimage.iso  > duplicator_log && eject $dvd3  

    if [ $LS ]
    then    
        eject $dvd1
        eject $dvd2
        eject $dvd3
        echo "Flip the DVDs over and close the drive trays."
        
        ls_prep $dvd1
        ls_prep $dvd2
        ls_prep $dvd3

        4L-cli print $dvd1 labels/$LS.bmp &
        4L-cli print $dvd2 labels/$LS.bmp &
        4L-cli print $dvd3 labels/$LS.bmp
    fi

    else
        eject $dvd1
        eject $dvd2
        eject $dvd3
        eject $dvd4
     
        dvd_prep $dvd1 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd2 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd3 1
        echo "Number $count"
        let "count+=1"

        dvd_prep $dvd4 1
        echo "Number $count"
        let "count+=1"

        growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd1=dvdimage.iso  > duplicator_log  && eject $dvd1 &
    growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd2=dvdimage.iso  > duplicator_log && eject $dvd2 &
    growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd3=dvdimage.iso  > duplicator_log && eject $dvd3
    & growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z $dvd4=dvdimage.iso  > duplicator_log && eject $dvd4

    if [ $LS ]
    then    
        eject $dvd1
        eject $dvd2
        eject $dvd3
        eject $dvd4
        echo "Flip the DVDs over and close the drive trays."
        
        ls_prep $dvd1
        ls_prep $dvd2
        ls_prep $dvd3
        ls_prep $dvd4

        4L-cli print $dvd1 labels/$LS.bmp &
        4L-cli print $dvd2 labels/$LS.bmp &
        4L-cli print $dvd3 labels/$LS.bmp &
        4L-cli print $dvd4 labels/$LS.bmp
    fi
    fi
done
echo "Done"
rm dvdimage.iso


If you just want a script that will handle Lightscribe and nothing else:

#!/bin/bash

LS=$1
dvd1=/dev/sr0
dvd2=/dev/sr2
dvd3=/dev/sr1
dvd4=/dev/sr3

ls_prep(){
    local dvd_to_load=$1
    media_ready=0
    while [ $media_ready -eq 0 ]   
    do
        media_ready=`4L-cli mediainfo $dvd_to_load | grep media | cut -d' ' -f3`
    done
}

echo "How many copies?"
read copies
count=1
while [ $count -le $copies ]
do
    remaining=0
    if [ $copies -gt 1 ]
    then
        remaining=$((copies-count))
    fi

    if [ $copies -eq 1 -o $remaining -eq 0 ]
    then
        eject $dvd1
        ls_prep $dvd1
        4L-cli print -q best $dvd1 "/home/ftp/$LS.bmp" && eject $dvd1
        echo "Number $count"
        let "count+=1"

    elif [ $copies -eq 2 -o $remaining -eq 1 ]
    then
        eject $dvd1
        eject $dvd2
        ls_prep $dvd1
        echo "Number $count"
        let "count+=1"
        ls_prep $dvd2
        echo "Number $count"
        let "count+=1"
        4L-cli print -q best $dvd1 "/home/ftp/$LS.bmp" && eject $dvd1 &
        4L-cli print -q best $dvd2 "/home/ftp/$LS.bmp" && eject $dvd2

    elif [ $copies -eq 3 -o $remaining -eq 2 ]
    then
        eject $dvd1
        eject $dvd2
        eject $dvd3
        ls_prep $dvd1
        echo "Number $count"
        let "count+=1"
        ls_prep $dvd2
        echo "Number $count"
        let "count+=1"
        ls_prep $dvd3
        echo "Number $count"
        let "count+=1"
        4L-cli print -q best $dvd1 "/home/ftp/$LS.bmp" && eject $dvd1 &
        4L-cli print -q best $dvd2 "/home/ftp/$LS.bmp" && eject $dvd2 &
        4L-cli print -q best $dvd3 "/home/ftp/$LS.bmp" && eject $dvd3

    else
        eject $dvd1
        eject $dvd2
        eject $dvd3
        eject $dvd4

        ls_prep $dvd1
        echo "Number $count"
        let "count+=1"
        ls_prep $dvd2
        echo "Number $count"
        let "count+=1"
        ls_prep $dvd3
        echo "Number $count"
        let "count+=1"
        ls_prep $dvd4
        echo "Number $count"
        let "count+=1"

        4L-cli print -q best $dvd1 "/home/ftp/$LS.bmp" && eject $dvd1 &
        4L-cli print -q best $dvd2 "/home/ftp/$LS.bmp" && eject $dvd2 &
        4L-cli print -q best $dvd3 "/home/ftp/$LS.bmp" && eject $dvd3 &
        4L-cli print -q best $dvd4 "/home/ftp/$LS.bmp" && eject $dvd4

    fi
done





Notes
  • For maximum possible happiness, run the script with Lightscribe as root. 4L-cli is unnecessarily root bound for printing.
  • Remember to "chmod 777 duplicator_script" or "chmod a+x duplicator_script" for maximum possible happiness
  • This is a multi threaded application. Remember the rule of thumb: max 2 threads per processor core... for maximum possible happiness.
Reactions:

24 comments:

  1. I have a Primera Bravo SE Disc Publisher and would buy a script from you that could control it. I want to load it with 20 DVDs that I need to rip for backup purposes. I have read it is possible but thought you might have experience to explain how I can learn to do this. I have shell programming experience but am not sure how to figure out the commands that control the Primera Bravo SE

    ReplyDelete
  2. From what I can tell, the Primera Bravo SE Disc Publisher should show up as /dev/sr0. After all, it is just an optical burner. This script should work in a trimmed-down fashion.

    ReplyDelete
  3. I'm getting an error, not sure what it is. I only have 3 drives, do I need any modifications? I figured it would be fine as long as I only chose < 4 copies.

    line 59: syntax error near unexpected token `elif'
    line 59: ` elif [ $copies -eq 3 -o $remaining -eq 2 ]'

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Try this test script to simulate a multiburn with 3 drives.


      #!/bin/bash

      LS=$1
      dvd1=/dev/sr0
      dvd2=/dev/sr2
      dvd3=/dev/sr1

      dvd_prep(){
      local dvd_to_load=$1
      local state=$2
      dvd_load=0
      sleep 5
      while [ $dvd_load -eq 0 ]
      do
      dvd_load=`udisks --show-info $dvd_to_load | grep -c "blank: *$state"`
      done
      }

      ls_prep(){
      local dvd_to_load=$1
      eject $dvd_to_load
      media_ready=0
      while [ $media_ready -eq 0 ]
      do
      media_ready=`4L-cli mediainfo $dvd_to_load | grep media | cut -d' ' -f3`
      done
      }

      echo "Load DVD into top tray"
      eject $dvd1
      dvd_prep $dvd1 0
      echo "Copying DVD to image"
      dd if=$dvd1 of=dvdimage.iso bs=512
      eject $dvd1

      echo "How many copies?"
      read copies
      count=1
      while [ $count -le $copies ]
      do
      remaining=0
      if [ $copies -gt 1 ]
      then
      remaining=$((copies-count))
      fi
      echo $remaining
      if [ $copies -eq 1 -o $remaining -eq 0 ]
      then
      eject $dvd1
      dvd_prep $dvd1 1
      echo "Number $count"
      growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z /dev/null=dvdimage.iso > duplicator_log
      eject $dvd1
      if [ $LS ]
      then
      echo "Turn DVD over and close the drive tray."
      ls_prep $dvd1
      4L-cli print -q best $dvd1 "/home/ftp/$LS.bmp" && eject $dvd1
      fi
      let "count+=1"

      elif [ $copies -eq 2 -o $remaining -eq 1 ]
      then
      eject $dvd1 &
      eject $dvd2

      dvd_prep $dvd1 1
      echo "Number $count"
      let "count+=1"

      dvd_prep $dvd2 1
      echo "Number $count"
      let "count+=1"
      growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z /dev/null=dvdimage.iso > duplicator_log && eject $dvd1 &
      growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z /dev/null=dvdimage.iso > duplicator_log && eject $dvd2

      if [ $LS ]
      then
      echo "Turn DVDs over and close the drive trays."
      ls_prep $dvd1
      ls_prep $dvd2
      4L-cli print -q best $dvd1 "/home/ftp/$LS.bmp" && eject $dvd1 &
      4L-cli print -q best $dvd2 "/home/ftp/$LS.bmp" && eject $dvd2
      fi

      else
      eject $dvd1 &
      eject $dvd2 &
      eject $dvd3

      dvd_prep $dvd1 1
      echo "Number $count"
      let "count+=1"

      dvd_prep $dvd2 1
      echo "Number $count"
      let "count+=1"

      dvd_prep $dvd3 1
      echo "Number $count"
      let "count+=1"

      growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z /dev/null=dvdimage.iso > duplicator_log && eject $dvd1 &
      growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z /dev/null=dvdimage.iso > duplicator_log && eject $dvd2 &
      growisofs -dvd-compat -use-the-force-luke=bufsize:32m -use-the-force-luke=notray -Z /dev/null=dvdimage.iso > duplicator_log && eject $dvd3

      if [ $LS ]
      then
      echo "Turn DVDs over and close the drive trays."
      ls_prep $dvd1
      ls_prep $dvd2
      ls_prep $dvd3
      4L-cli print -q best $dvd1 "/home/ftp/$LS.bmp" && eject $dvd1 &
      4L-cli print -q best $dvd2 "/home/ftp/$LS.bmp" && eject $dvd2 &
      4L-cli print -q best $dvd3 "/home/ftp/$LS.bmp" && eject $dvd3
      fi
      fi
      done
      rm dvdimage.iso
      echo "Done"


      Let me know if this works. If it does, I'll send over the code for the real deal.

      -Justin

      Delete
  4. Is it possible to use a similar script to do CD duplication? I'm getting the following error "dd: reading `/dev/sr0': Input/output error
    0+0 records in
    0+0 records out
    0 bytes (0 B) copied, 0.0272848 s, 0.0 kB/s"
    when attempting to run this command "dd if=/dev/sr0 of=dvdimage.iso bs=512". Do I need to use a different tool because I'm trying to copy a CD instead of a DVD? For my test I was using a CD/R with one of my pastor's sermons burned on it. I have 2 drives currently in the machine and I was able to use the eject command to verify which one was which. Thanks in advance for any help you're able to offer.
    P.S. Should there be a "then" in your script after each of the "elif"s (elif [ $copies -eq 3 -o $remaining -eq 2 ] )?

    ReplyDelete
  5. To find what your drives are showing up as, try running just "df" and you should see something like this in the list:
    /dev/sr0 4268896 4268896 0 100% /media/CDROM

    This script will work with a CD. I ran through a bunch of them in testing. Here's the original in full downloadable and working form. Modify to fit your needs:
    http://hackersare.us/blog/duplicator

    And here's the test script:
    http://hackersare.us/blog/duplicator_test

    Let me know if you have any problems.

    ReplyDelete
    Replies
    1. I tried running "df"
      Filesystem 1K-blocks Used Available Use% Mounted on
      /dev/sda1 38543496 2002320 34609708 6% /
      udev 230308 8 230300 1% /dev
      tmpfs 95032 320 94712 1% /run
      none 5120 0 5120 0% /run/lock
      none 237572 0 237572 0% /run/shm

      Does this have anything to do with the CD drives being mounted or not? Sorry I'm still really new to Ubuntu and Linux in general. Although I am finding it very fascinating and interesting. After reading through the script you posted about a dozen time I think I finally understand most of what is going on and what the different commands are doing. :) Thanks for your prompt response.

      Delete
    2. Try throwing a CD in it and see if you get a different result.

      Delete
    3. There is a CD in it(and I just stuck another CD in the other drive). No change. I'm thinking this is not a good sign. :)

      Delete
    4. Not good in deed. Is it reading the CD?

      Delete
  6. I thought so.. I can hear the CDs spin up after I insert them. But I'm beginning to have my doubts. I've tried hooking up a couple of other older(10+ years old I think) IDE CD drives that I had lying around using an IDE - USB adapter. No luck. Am I correct in assuming that /dev/sda1 is the internal hard drive? Any other tests I can run other than "df"? I run the latest version of Ubuntu Server headless and using SSH to control it.

    ReplyDelete
    Replies
    1. At least one of the drives was working as of a couple of days ago because I used it to install Ubuntu from a CD. I'm currently testing some of the things you've had me try on another slightly newer computer running Ubuntu that I'm currently running as a development server for a web project I'm working on for one of my computer professors over the summer.

      Delete
    2. Shouldn't hurt anything. I'm trying to find an easier way. Sometimes old drives like that show up as "hdb" or something like that.

      Delete
    3. Ok, so nothing showed up when running "df" on my other machine(CD drive is also IDE) however when I ran "dd if=/dev/sr0 of=dvdimage.iso bs=512" it actually worked! Yeah! So perhaps its time I permanently retire some of these old drives... Thanks so much for your help. I really enjoyed this article and also the one about your unpaid internship. :) I'll check back later and look forward to more interesting posts in the future.

      Delete
  7. hello i need yout help for script bash new script, duplicator, but how i will send you file sh?

    ReplyDelete
  8. Thank you for your outstanding post. I am really thankful to you for this post.

    ReplyDelete
  9. CD and DVD are the most popular way to storing music, videos and documents. By storing on them on to a CD or DVD we can also share out precise moment with our friends and relatives. CD & DVD Duplication

    ReplyDelete
  10. Hi. Great script specially for server side. Is it possible for you to add infinite counts and only stop if you tell it?

    Thanks

    ReplyDelete
  11. Now I wonder if this would work with a Raspberry Pi and 4 USB drives ?

    ReplyDelete
    Replies
    1. The setup would probably be a lot simpler.

      Delete
  12. Oven toaster has larger toasting space therefore it can toast more food varieties and can perform other processes like broiling and grilling.top 5 toastmaster machines

    ReplyDelete

Subscribe to RSS Feed Follow me on Twitter!