<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>edsalisbury.net &#187; Linux</title>
	<atom:link href="http://edsalisbury.net/category/linux/feed/" rel="self" type="application/rss+xml" />
	<link>http://edsalisbury.net</link>
	<description>your guide to user-friendly entertainment</description>
	<lastBuildDate>Thu, 01 Dec 2011 22:08:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Cool Tools: VIM</title>
		<link>http://edsalisbury.net/cool-tools-vim/</link>
		<comments>http://edsalisbury.net/cool-tools-vim/#comments</comments>
		<pubDate>Fri, 18 Nov 2011 02:23:50 +0000</pubDate>
		<dc:creator>Ed</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://www.edsalisbury.net/?p=292</guid>
		<description><![CDATA[<a href="http://edsalisbury.net/cool-tools-vim/" title="Cool Tools: VIM"></a>One thing that I cannot live without is a text editor, namely VIM.  VIM was first released as free and extended version of the VI program found on all Unix machines.  I first cut my teeth on VI when I &#8230;<p class="read-more"><a href="http://edsalisbury.net/cool-tools-vim/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://edsalisbury.net/cool-tools-vim/" title="Cool Tools: VIM"></a><p><a href="http://vim.org"><img class="alignright size-thumbnail wp-image-583" title="VIM" src="http://edsalisbury.net/wp-content/uploads/2011/11/vim-editor_logo-150x150.png" alt="" width="150" height="150" /></a>One thing that I cannot live without is a text editor, namely VIM.  VIM was first released as free and extended version of the VI program found on all Unix machines.  I first cut my teeth on VI when I started my sysadmin career, and switched to VIM a couple of years later.  VIM by default works mostly like VI, but i&#8217;ts highly configurable, and has a lot of power, especially when you start working with your .vimrc.  Since starting with the editor, I&#8217;ve carried my .vimrc from machine to machine, and company to company.  I&#8217;m continually updating it, and while there&#8217;s not a ton of stuff here, I thought I&#8217;d share it in case someone gets some value:</p>
<pre>" Ed Salisbury's .vimrc
" Last Modified: 11/17/11

" Make VIM act like VIM, not VI
set nocompatible

" Set up TABs
set tabstop=4
set shiftwidth=4
set softtabstop=4
set expandtab
set smarttab
set autoindent
set smartindent

" Set up syntax highlighting
syntax on
filetype plugin on
filetype indent on
set formatoptions=qroc
set cindent

" Misc settings
set number       " Print line numbers
set background=dark
set pastetoggle=&lt;F2&gt;</pre>
<p>I&#8217;d consider these settings a starting point for doing code/web development. Of course, there are tons of more complicated .vimrc files out there, but this should be good for starters. If you&#8217;re interested as to what each of these settings do, you can type :helpin VIM and it will display the help file.</p>
]]></content:encoded>
			<wfw:commentRss>http://edsalisbury.net/cool-tools-vim/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Setting up Differential Backups for Websites</title>
		<link>http://edsalisbury.net/setting-up-differential-backups-for-websites/</link>
		<comments>http://edsalisbury.net/setting-up-differential-backups-for-websites/#comments</comments>
		<pubDate>Mon, 14 Sep 2009 05:46:35 +0000</pubDate>
		<dc:creator>Ed</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[disaster recovery]]></category>
		<category><![CDATA[website]]></category>

		<guid isPermaLink="false">http://www.edsalisbury.net/?p=452</guid>
		<description><![CDATA[<a href="http://edsalisbury.net/setting-up-differential-backups-for-websites/" title="Setting up Differential Backups for Websites"></a>Backups. No one likes doing them, but they&#8217;re too important not to do. Typically when I&#8217;m doing stuff for my websites, I will occasionally do a tar of a directory and save it off, or even set up a script &#8230;<p class="read-more"><a href="http://edsalisbury.net/setting-up-differential-backups-for-websites/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://edsalisbury.net/setting-up-differential-backups-for-websites/" title="Setting up Differential Backups for Websites"></a><p><a href="http://www.flickr.com/photos/roadhunter/68017710/"><img src="http://www.edsalisbury.net/wp-content/uploads/2009/09/backup-150x144.jpg" alt="Backup Backup Backup by Topato" title="Backup Backup Backup by Topato" width="150" height="144" class="alignright size-thumbnail wp-image-453" /></a><br />
Backups.  No one likes doing them, but they&#8217;re too important not to do.  Typically when I&#8217;m doing stuff for my websites, I will occasionally do a tar of a directory and save it off, or even set up a script that will do this nightly.  Then I have issues with disks filling up, and not wanting to delete my backups for fear of losing something (like the 20 copies aren&#8217;t enough!)<br />
<span id="more-452"></span><br />
Recently, I decided to put an end to my backup worries, and write a differential backup system.  What is a differential backup?  Go go gadget <a href="http://en.wikipedia.org/wiki/Incremental_backup">Wikipedia</a>!  Basically, a differential backup means that I won&#8217;t be filling up my drives any time soon, because I&#8217;m not doing a FULL backup each time &#8212; it&#8217;s only backing up the changes that have been made since the last full backup, which runs weekly and monthly.  I&#8217;ve been running and tuning the script for a while, and wanted to make sure that it&#8217;s working properly.  If you decide to use this script, you <strong>MUST</strong> test the restores with it, as I can&#8217;t be responsible if you lose data and the script somehow fails you.  You have been warned!  Without further ado, the script:</p>
<pre class="brush:perl; gutter: false; wrap-lines: true; ruler: false">
#!/usr/bin/perl
# Website Differential Backup
# Keeps several websites and their databases backed up
# by Ed Salisbury (ed@edsalisbury.net)
# http://www.edsalisbury.net
# (c)2009 Ed Salisbury, Some Rights Reserved
#
# Config File Format
# DIR /path/to/dir
# DB dbname
#
# Limitations:
# * Cannot do differential backups of databases
#
#
# License:
# Except where otherwise noted, this work is licensed under Creative Commons
#   Attribution ShareAlike 3.0.
#
# You are free:
#   * to Share - to copy, distribute and transmit the work
#   * to Remix - to adapt the work
#
# Under the following conditions:
#   * Attribution. You must attribute the work in the manner specified by the
#     author or licensor (but not in any way that suggests that they endorse
#     you or your use of the work).
#   * Share Alike. If you alter, transform, or build upon this work, you may
#     distribute the resulting work only under the same, similar or a
#     compatible license.
#   * For any reuse or distribution, you must make clear to others the license
#     terms of this work. The best way to do this is with a link to the
#     license's web page (http://creativecommons.org/licenses/by-sa/3.0/)
#   * Any of the above conditions can be waived if you get permission from the
#   * Nothing in this license impairs or restricts the author's moral rights.

use strict;
use warnings;

# Place to store backups
my $BACKUP_DIR = &quot;/backup&quot;;
# Configuration file to read what to backup
my $BACKUP_CONF = &quot;/usr/local/etc/backup.conf&quot;;
# Database user/pass
my $DB_USER = 'root';
my $DB_PASS = '**DBPASSWD**';

# Turn off output buffering
$|++;

# Tools
my $TAR = '/bin/tar';
my $GZIP = '/bin/gzip';
my $LS = '/bin/ls';
my $HEAD = '/usr/bin/head';
my $MKDIR = '/bin/mkdir';
my $RM = '/bin/rm';
my $MYSQLDUMP = '/usr/local/mysql/bin/mysqldump';

my @months = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
my @days = qw( Sun Mon Tue Wed Thu Fri Sat );
my @dirs;
my @dbs;

# Get current date
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime time;
my $datestamp = sprintf(&quot;%04d%02d%02d&quot;, $year+1900, $mon+1, $mday);
my $day = $days[$wday];

# Read config file
unless (open(CFG, $BACKUP_CONF))
{
    print &quot;Error: Cannot open $BACKUP_CONFn&quot;;
    exit(1);
}
while (&lt;CFG&gt;)
{
    chomp;
    if (/^DIRs+(.*)$/i)
    {
        push (@dirs, $1);
    }
    elsif (/^DBs+(.*)$/i)
    {
        push (@dbs, $1);
    }
}
close (CFG);

# Do Directory Backups
foreach my $dir (@dirs)
{
    print &quot;Backing up $dir... &quot;;

    # Add backslashes for spaces
    $dir =~ s/ /\ /g;

    my $backup_src = $dir;

    # Convert slashes to underscores
    $dir =~ s///_/g;
    # Remove leading slash
    $dir = substr($dir,1);

    unless (-d &quot;$BACKUP_DIR/$dir&quot;)
    {
        system(&quot;$MKDIR -p $BACKUP_DIR/$dir&quot;);
    }

    # Get datestamp of last full backup
    my $last_full = `$LS -t $BACKUP_DIR/$dir/${dir}_full* 2&gt;&amp;1 | $HEAD -1`;
    chomp($last_full);
    if ($last_full =~ /No such file or directory/)
    {
        $last_full = '';
    }
    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
        $blksize,$blocks) = stat($last_full);

    if ($mday == 1)
    {
        # Monthly Full Backup
        system(&quot;$TAR -cf $BACKUP_DIR/$dir/${dir}_full_monthly_$datestamp.tar $backup_src &gt; /dev/null 2&gt;&amp;1&quot;);
        system(&quot;$GZIP -f $BACKUP_DIR/$dir/${dir}_full_monthly_$datestamp.tar&quot;);
        system(&quot;$RM $BACKUP_DIR/$dir/${dir}_full_weekly_*&quot;);
    }
    elsif ($wday == 0 || !$last_full)
    {
        # Weekly Full Backup
        system(&quot;$TAR -cf $BACKUP_DIR/$dir/${dir}_full_weekly_$datestamp.tar $backup_src  &gt; /dev/null 2&gt;&amp;1&quot;);
        system(&quot;$GZIP -f $BACKUP_DIR/$dir/${dir}_full_weekly_$datestamp.tar&quot;);
    }

    # Daily Differential Backup
    if ($mtime)
    {
        my $newer = sprintf(&quot;%02d-%s&quot;, (localtime($mtime))[3], $months[(localtime($mtime))[4]]);
        system(&quot;$TAR --newer $newer -cf $BACKUP_DIR/$dir/${dir}_diff_daily_$day.tar $backup_src &gt; /dev/null 2&gt;&amp;1&quot;);
    }
    else
    {
        system(&quot;$TAR -cf $BACKUP_DIR/$dir/${dir}_diff_daily_$day.tar $backup_src &gt; /dev/null 2&gt;&amp;1&quot;);
    }
    system(&quot;$GZIP -f $BACKUP_DIR/$dir/${dir}_diff_daily_$day.tar&quot;);

    print &quot;done.n&quot;;
}

# Do Database Backups
foreach my $db (@dbs)
{
    my $db_name = $db;
    $db = &quot;db_$db&quot;;

    unless (-d &quot;$BACKUP_DIR/$db&quot;)
    {
        system(&quot;$MKDIR -p $BACKUP_DIR/$db&quot;);
    }

    print &quot;Backing up $db_name database... &quot;;

    if ($mday == 1)
    {
        # Monthly Backup
        system(&quot;$MYSQLDUMP --user=$DB_USER --password='$DB_PASS' $db_name &gt; $BACKUP_DIR/$db/${db}_monthly_$datestamp.sql&quot;);
        system(&quot;$GZIP -f $BACKUP_DIR/$db/${db}_monthly_$datestamp.sql&quot;);
        system(&quot;$RM $BACKUP_DIR/$db/${db}_weekly_*&quot;);
    }
    elsif ($wday == 0)
    {
        # Weekly Backup
        system(&quot;$MYSQLDUMP --user=$DB_USER --password='$DB_PASS' $db_name &gt; $BACKUP_DIR/$db/${db}_weekly_$datestamp.sql&quot;);
        system(&quot;$GZIP -f $BACKUP_DIR/$db/${db}_weekly_$datestamp.sql&quot;);
    }

    # Daily Backup
    system(&quot;$MYSQLDUMP --user=$DB_USER --password='$DB_PASS' $db_name &gt; $BACKUP_DIR/$db/${db}_daily_$day.sql&quot;);
    system(&quot;$GZIP -f $BACKUP_DIR/$db/${db}_daily_$day.sql&quot;);

    print &quot;done.n&quot;;
}
</pre>
<p>Call the script something like /usr/local/bin/backup, and then create a config file /usr/local/etc/backup.conf, that has the following format:<br />
DIR /www/domain1.com<br />
DIR /www/domain2.com<br />
DB domain1_wp_db<br />
DB domain2_wp_db</p>
<p>(Substituting locations/db names appropriate for your environment of course).   If you use a different config file than /usr/local/etc/backup.conf, be sure to change that line in the script.  Also, you&#8217;ll need to change the mysql root password in the script to be whatever it is for your env (or make it non-root, whichever you want, it just needs to be able to do a mysqldump on the databases)</p>
<p>Next, set up your crontab to run nightly:</p>
<pre>sudo crontab -e</pre>
<p>Add the following line:</p>
<pre>0 1 * * * /usr/local/bin/backup &gt; /dev/null 2&gt;&#038;1</pre>
<p>That should be it!  Again, make sure to do some test restores to verify that it works ok!  Here&#8217;s what a typical backup directory looks like after a couple of months running the script:</p>
<pre>[ed@halo1:/backup/www_edsalisbury.net]$ ls -l
total 144240
-rw-r--r--  1 root root  5423759 Sep 11 01:00 www_edsalisbury.net_diff_daily_Fri.tar.gz
-rw-r--r--  1 root root  1839115 Sep  7 01:00 www_edsalisbury.net_diff_daily_Mon.tar.gz
-rw-r--r--  1 root root  5787136 Sep 12 01:00 www_edsalisbury.net_diff_daily_Sat.tar.gz
-rw-r--r--  1 root root  7193167 Sep 13 01:00 www_edsalisbury.net_diff_daily_Sun.tar.gz
-rw-r--r--  1 root root  3782727 Sep 10 01:00 www_edsalisbury.net_diff_daily_Thu.tar.gz
-rw-r--r--  1 root root  2455973 Sep  8 01:00 www_edsalisbury.net_diff_daily_Tue.tar.gz
-rw-r--r--  1 root root  3268897 Sep  9 01:00 www_edsalisbury.net_diff_daily_Wed.tar.gz
-rw-r--r--  1 root root 23705401 Aug  1 01:00 www_edsalisbury.net_full_monthly_20090801.tar.gz
-rw-r--r--  1 root root 33975458 Sep  1 01:00 www_edsalisbury.net_full_monthly_20090901.tar.gz
-rw-r--r--  1 root root 31453170 Sep  6 01:00 www_edsalisbury.net_full_weekly_20090906.tar.gz
-rw-r--r--  1 root root 28556424 Sep 13 01:00 www_edsalisbury.net_full_weekly_20090913.tar.gz
</pre>
<p>Not too bad, size-wise.  For all of my sites, the backup directory is about 4 GB, and will stay around that size for quite a while.  The differentials get deleted and so do the weekly full backups after the monthly full completes.  This makes it so that the directory only really grows when there&#8217;s a new full monthly.   If you find this script useful or have issues, be sure to post a comment!</p>
]]></content:encoded>
			<wfw:commentRss>http://edsalisbury.net/setting-up-differential-backups-for-websites/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Set Up Virtual Web Hosting with Apache</title>
		<link>http://edsalisbury.net/how-to-set-up-virtual-web-hosting-with-apache/</link>
		<comments>http://edsalisbury.net/how-to-set-up-virtual-web-hosting-with-apache/#comments</comments>
		<pubDate>Thu, 20 Aug 2009 15:58:50 +0000</pubDate>
		<dc:creator>Ed</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://www.edsalisbury.net/?p=419</guid>
		<description><![CDATA[<a href="http://edsalisbury.net/how-to-set-up-virtual-web-hosting-with-apache/" title="How to Set Up Virtual Web Hosting with Apache"></a>Up until a couple of years ago, I used shared web hosting for serving up my various sites. I went through several of them because for whatever reason, they turned out to not be what I wanted. I finally came &#8230;<p class="read-more"><a href="http://edsalisbury.net/how-to-set-up-virtual-web-hosting-with-apache/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://edsalisbury.net/how-to-set-up-virtual-web-hosting-with-apache/" title="How to Set Up Virtual Web Hosting with Apache"></a><p><img src="http://www.edsalisbury.net/wp-content/uploads/2009/08/apache_logo.png" alt="Apache" title="Apache" width="150" height="149" class="alignright size-full wp-image-430" /><br />
Up until a couple of years ago, I used shared web hosting for serving up my various sites.  I went through several of them because for whatever reason, they turned out to not be what I wanted.  I finally came to the realization that I needed to get my own dedicated host.  I found a good provider (<a href="http://www.shareasale.com/r.cfm?B=106084&#038;U=369672&#038;M=15362">The Planet</a>), and started migrating over my websites (along with my friend Chris&#8217; sites).  Something I knew I would have to learn is how to set up Apache to be able to do virtual hosting.  In this guide, I&#8217;ll show you how I did it, and the script I created to make things easier.<br />
<span id="more-419"></span><br />
The first thing to do is to set up a logical directory structure &#8212; I hate putting web docs in some silly folder like /usr/local/apache2/htdocs &#8212; that&#8217;s always seemed like such a weird place to put things (I guess it goes against my feelings that anything in /usr shouldn&#8217;t be writable by users)   Since this is a webserver, I wanted something closer to the root, like /www/&lt;domain&gt;.  I also wanted to have a different directory structure and logging for each virtual host, I chose /www/logs/&lt;domain&gt;.</p>
<p>The next thing is to set up the apache config file to be able to include a separate file just for vhosts.  Add this section somewhere in your httpd.conf file:</p>
<pre>
# Virtual Hosts
NameVirtualHost *
Include etc/httpd-vhosts.conf
</pre>
<p>Now, create httpd-vhosts.conf in the apache config dir, and create a manual entry to make sure it works:</p>
<pre>
<VirtualHost *>
    ServerName      www.mydomain.com
    ServerAdmin     webmaster@mydomain.com
    ServerAlias     mydomain.com
    DocumentRoot    /www/mydomain.com/docs
    DirectoryIndex  index.html index.php
    AccessFileName  .htaccess
    HostnameLookups Off
    ErrorLog        /www/logs/mydomain.com/error.log
    LogLevel        warn
    CustomLog       /www/logs/mydomain.com/access.log combined
</VirtualHost>
</pre>
<p>(Be sure to change &#8220;mydomain.com&#8221; to your domain)</p>
<p>Create /www/&lt;domain.com&gt; and log files, as well as change ownerships properly:</p>
<pre>
# mkdir /www/logs/&lt;domain.com&gt;
# mkdir /www/&lt;domain.com&gt;
# chmod g+w /www/&lt;domain.com&gt;
# chown nobody:nobody /www/&lt;domain.com&gt;
# chown nobody:nobody /www/logs/&lt;domain.com&gt;
</pre>
<p>Next, create some sort of test file (like index.html) in the new doc directory.</p>
<p>When you&#8217;re ready, restart the webserver (usually just by running apachectl graceful)  With any luck, you should be seeing the webpage you created when you go do www.&lt;domain.com&gt;.  If not, look at the apache config for errors, and verify that the DNS entries are correct.</p>
<p>Now, as you were expecting, I have a script to be able to automate this.  It&#8217;s pretty simple, but handy.  I call it &#8220;add_vhost&#8221; and I put it into /usr/local/bin:</p>
<pre class="brush:perl; gutter: false; wrap-lines: true; ruler: false">
#!/usr/bin/perl -w
# AddVhost
# Add Virtual Host Configs for Apache
# by Ed Salisbury (ed@edsalisbury.net)
# http://www.edsalisbury.net
# (c)2009 Ed Salisbury, Some Rights Reserved
#
# License:
# Except where otherwise noted, this work is licensed under Creative Commons
#   Attribution ShareAlike 3.0.
#
# You are free:
#   * to Share -- to copy, distribute and transmit the work
#   * to Remix -- to adapt the work
#
# Under the following conditions:
#   * Attribution. You must attribute the work in the manner specified by the
#     author or licensor (but not in any way that suggests that they endorse
#     you or your use of the work).
#   * Share Alike. If you alter, transform, or build upon this work, you may
#     distribute the resulting work only under the same, similar or a
#     compatible license.
#   * For any reuse or distribution, you must make clear to others the license
#     terms of this work. The best way to do this is with a link to the
#     license's web page (http://creativecommons.org/licenses/by-sa/3.0/)
#   * Any of the above conditions can be waived if you get permission from the
#     copyright holder.
#   * Nothing in this license impairs or restricts the author's moral rights.

use strict;

my $DOCROOT = '/www';
my $LOGDIR = '/www/logs';
my $USER = 'nobody';
my $GROUP = 'nobody';
my $VHOST_CFG = &quot;/usr/local/apache2/etc/httpd-vhosts.conf&quot;;

my $domain = $ARGV[0];

if (!$domain)
{
    print &quot;Error: No domain specified!n&quot;;
    exit(1);
}
open (OUT, &quot;&gt;&gt; $VHOST_CFG&quot;);
print OUT &quot;n&quot;;
print OUT &quot;&lt;VirtualHost *&gt;n&quot;;
print OUT &quot;tServerName      www.$domainn&quot;;
print OUT &quot;tServerAdmin     webmaster@$domainn&quot;;
print OUT &quot;tServerAlias     $domainn&quot;;
print OUT &quot;tDocumentRoot    $DOCROOT/$domainn&quot;;
print OUT &quot;tDirectoryIndex  index.html index.phpn&quot;;
print OUT &quot;tAccessFileName  .htaccessn&quot;;
print OUT &quot;tHostnameLookups Offn&quot;;
print OUT &quot;tErrorLog        $LOGDIR/$domain/error.logn&quot;;
print OUT &quot;tLogLevel        warnn&quot;;
print OUT &quot;tCustomLog       $LOGDIR/$domain/access.log combinedn&quot;;
print OUT &quot;&lt;/VirtualHost&gt;n&quot;;
close (OUT);

system(&quot;mkdir $LOGDIR/$domain&quot;);
system(&quot;mkdir $DOCROOT/$domain&quot;);
system(&quot;chmod g+w $DOCROOT/$domain&quot;);
system(&quot;chown $USER:$GROUP $DOCROOT/$domain&quot;);
system(&quot;chown $USER:$GROUP $LOGDIR/$domain&quot;);
</pre>
<p>Be sure to change the config variables to suit your environment.  When you want to add a virtual host, simply run:</p>
<pre>
% sudo add_vhost domain.com
</pre>
<p>It will create the config and set everything up for you.  All you need to do then is to restart the webserver, and you&#8217;re good to go!</p>
]]></content:encoded>
			<wfw:commentRss>http://edsalisbury.net/how-to-set-up-virtual-web-hosting-with-apache/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Linux RetroGaming: Atari 8-Bit</title>
		<link>http://edsalisbury.net/linux-retrogaming-atari-8-bit/</link>
		<comments>http://edsalisbury.net/linux-retrogaming-atari-8-bit/#comments</comments>
		<pubDate>Mon, 17 Aug 2009 20:19:56 +0000</pubDate>
		<dc:creator>Ed</dc:creator>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Atari]]></category>
		<category><![CDATA[atari800]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[Wico]]></category>

		<guid isPermaLink="false">http://www.edsalisbury.net/?p=363</guid>
		<description><![CDATA[<a href="http://edsalisbury.net/linux-retrogaming-atari-8-bit/" title="Linux RetroGaming: Atari 8-Bit"></a>I&#8217;ve been into emulation again lately, and I started with my first favorite system of all time, the Atari 8-bit computer. When I was growing up, I had 2 different 8-bit machines: The Atari 400: and later the Atari 130XE: &#8230;<p class="read-more"><a href="http://edsalisbury.net/linux-retrogaming-atari-8-bit/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://edsalisbury.net/linux-retrogaming-atari-8-bit/" title="Linux RetroGaming: Atari 8-Bit"></a><p>I&#8217;ve been into emulation again lately, and I started with my first favorite system of all time, the Atari 8-bit computer.  When I was growing up, I had 2 different 8-bit machines:</p>
<p>The <strong>Atari 400:</strong><br />
<img src="http://www.edsalisbury.net/wp-content/uploads/2009/07/atari400open-300x201.jpg" alt="Atari 400" title="Atari 400" width="300" height="201" class="alignnone size-medium wp-image-364" /></p>
<p><span id="more-363"></span><br />
and later the <strong>Atari 130XE:</strong><br />
<img src="http://www.edsalisbury.net/wp-content/uploads/2009/07/Atari_130xe-300x196.jpg" alt="Atari 130 XE" title="Atari 130 XE" width="300" height="196" class="alignnone size-medium wp-image-365" /></p>
<p>I did a lot of things on these machines, including learn BASIC, type in programs from magazines, and of course&#8230; play games!   In order to play these games, I had a great joystick &#8211;</p>
<p>the <strong>Wico Command Control</strong> joystick:<br />
<a href="http://www.flickr.com/photos/fredf78/3681756098/"><img src="http://www.edsalisbury.net/wp-content/uploads/2009/08/www_flickr_com_photos_fredf78_3681756098-300x199.jpg" alt="Wico Command Control" title="Wico Command Control" width="300" height="199" class="alignnone size-medium wp-image-395" /></a></p>
<p>My goal is to have as close as an experience as possible to the real thing with modern hardware, through emulation.  To purists, this is considered sacrilege &#8212; they want the physical hardware, and emulation for them just doesn&#8217;t cut it.   I guess I&#8217;m not a purist &#8212; I just like being able to play the old games!  Since I&#8217;m now running Linux, the goal will be to get a working emulator going and everything working properly.  Here&#8217;s what I mean by a proper emulator setup:</p>
<ul>
<li>Emulator should run in fullscreen mode, with no window elements showing</li>
<li>2 joysticks should work</li>
<li>Everything should be able to be specified via the command line</li>
<li>It should handle multiple disk programs as painless as possible</li>
<li>It should have a standard method for exiting the emulator</li>
</ul>
<p>The emulator I&#8217;ll be using for the Atari 8-Bit computers is <a href="http://atari800.sourceforge.net">atari800</a>.  In my opinion, it is the best emulator for the 8-bits, and will work for us just fine, with a few modifications.  As a part of this project, I am also going to use the original joysticks that were used for the system.  </p>
<h5>Controllers:</h5>
<p>For this project, I&#8217;m using the Wico Command Control joystick (see photo above).  I used to use the Logitech gamepads that look like PS2 controllers, but after switching to the right controller, there&#8217;s no going back!  The issue is, I need a way to convert them to USB to be able to use them on modern machines.  After doing some searching, I found just the adapter, from a company called <a href="http://www.retrousb.com">RetroZone</a>.  I bought the joystick and adapter off of eBay, and I couldn&#8217;t wait to plug it in and try it out!  It seemed to work, but I noticed something odd &#8211; the fire button was being pressed every time I moved the joystick.  I thought that it might be a linux thing, so I plugged it into my Windows laptop, and sure enough, it presses a different button every time I move the joystick.  This wouldn&#8217;t be a problem normally, if the emulator I&#8217;m using didn&#8217;t allow you to use any button as the fire button.  I have a fix for this issue though, which I&#8217;ll get to later.</p>
<h5>Installation:</h5>
<p>To install the standard version of the emulator (atari800), simply run the following (in Ubuntu):</p>
<pre>
% sudo apt-get install atari800
</pre>
<p>Then before you can actually run it, you&#8217;ll need a couple of things:</p>
<ul>
<li>ROM files</li>
<li>Disk / Cartridge Images</li>
</ul>
<p>The ROM files are dumps from the actual ROM chips found in the original hardware.  There&#8217;s a few of them out there on the internet, and one place I&#8217;ve found that has them is <a href="http://www.theoldcomputer.com/Libarary%27s/Emulation/atari_8bit/roms/os/atari_8bit_roms_os.htm">TheOldComputer.com</a>.  All you really need are the following ROMs:</p>
<ul>
<li>Atari Rev B (400/800) NTSC</li>
<li>Atari XL or XE NTSC</li>
</ul>
<p>You&#8217;ll also need disk images or cartridge images.  One cool site that I use frequently is called <a href="http://www.atarimania.com">AtariMania.com</a>.  They have images and also artwork scans from the boxes/disks/manuals etc.</p>
<p>Now would be a good time to talk about how you&#8217;re planning on organizing your emulator directories.  I personally use the following directory structure, but you&#8217;re welcome to use whatever you like:</p>
<pre>
/data/Software/Retro/Atari 8-Bit/roms
/data/Software/Retro/Atari 8-Bit/disks
/data/Software/Retro/Atari 8-Bit/carts
/data/Software/Retro/Atari 8-Bit/art_front
/data/Software/Retro/Atari 8-Bit/art_back
/data/Software/Retro/Atari 8-Bit/snap
/data/Software/Retro/Atari 8-Bit/titles
</pre>
<p>The last 4 directories are useful when running the emulator from a front-end, which I highly recommend.  I&#8217;ll talk more about front-ends in a future blog posting.</p>
<p>To run the emulator, simply run the following:</p>
<pre>% atari800</pre>
<p>This will probably give you an error saying that it can&#8217;t find the ROM files.  You will need to set up the configuration so that it can find your ROMs.  To do this from within the emulator, hit F1, and go to &#8220;Emulator Configuration&#8221;.  From there you can select the different ROMs and configure things how you like.  To exit the emulator, press F9.</p>
<p>After it can find your roms, you&#8217;ll need to load a disk image.  To do this from the command line, simply run:</p>
<pre>
% atari800 &lt;name of the disk image&gt;
</pre>
<p>(If there are spaces in the diskname, be sure to either put double quotes around the filename or use backslashes in front of the spaces or other special characters)</p>
<p>A couple of keys to get you started:</p>
<ul>
<li>F1 &#8211; Configuration Mode</li>
<li>F2 &#8211; Option</li>
<li>F3 &#8211; Select</li>
<li>F4 &#8211; Start</li>
<li>F5 &#8211; Reset</li>
<li>F9 &#8211; Quit the Emulator</li>
</ul>
<p>With any luck, you&#8217;re now able to play some games!   A couple of issues you might be having:  It&#8217;s windowed and small, and you want it to be fullscreen and big!  It took a little bit of effort to get this going for me, but here&#8217;s how I achieved this.  If you are running with more than one monitor, please see my <a href="http://www.edsalisbury.net/linux/gaming-in-linux/">guide</a> on how to set up MetaModes to fix fullscreen issues.</p>
<p>First off, you will want to turn on NTSC mode.  To do this, either do it in the emulator itself (hit F1, etc.) or by editing the config file.  If you&#8217;re editing the config file, just set this line in ~/.atari800.cfg:</p>
<pre>
DEFAULT_TV_MODE=NTSC
</pre>
<p>If you&#8217;re like me, you want your gaming to be in fullscreen mode, not a window.  One way of doing this is to create an alias that sets the resolution:</p>
<pre>
alias atari800='atari800 -width 1280 -height 1024'
</pre>
<p>Add this line to your .bashrc, and you&#8217;ll be in fullscreen gaming heaven!  (Be sure to change the height and width as necessary for your monitor)</p>
<h5>Customization:</h5>
<p>At first, I just used the standard distribution version of atari800 &#8211; this worked well, but I had a couple of issues.  First, the emulator treats every joystick button as the fire button.  This was an issue with the joystick adapter I&#8217;m using, which sends a different button press for each direction (by design).  Another issue I had was the fact that there needed to be an easy way to swap disks in a multi-disk set &#8212; I would like to be able to hit a function key for this.</p>
<p>I figured the easiest way to get these things fixed would be to compile from source.  I started by downloading the source from <a href="http://sourceforge.net/scm/?type=cvs&#038;group_id=40606">CVS</a>, and started working on compiling.  (For my examples, I used version  2.1.0. To compile it, you&#8217;ll also need to get the <a href="http://www.libsdl.org/">SDL</a> development libraries, which can easily by installed via Synaptic Package Manager (search for SDL). There&#8217;s lots of guides on compiling from source out there, but the simple method is:</p>
<pre>
cd &lt;source dir&gt;
./configure
make
</pre>
<p>Before I do any source code hacking, I always make sure that the source compiles first, that way I know it works before I start breaking stuff!  Another thing to do is to always keep a backup copy of the source file you are editing.  You want to be able to back out of any changes you make.  On that note, let the hacking begin!</p>
<p>To fix the trigger issue, edit atari_sdl.c:<br />
In the get_platform_TRIG() function, change the following lines:</p>
<pre>int trig0, trig1, i;</pre>
<p>to:</p>
<pre>int trig0, trig1;</pre>
<p>and:</p>
<pre>
for (i = 0; i < joystick0_nbuttons; i++) {
    if (SDL_JoystickGetButton(joystick0, i)) {
        trig0 = 0;
        break;
    }
}
</pre>
<p>to simply:</p>
<pre>
if (SDL_JoystickGetButton(joystick0, 0))
    trig0 = 0;
</pre>
<p>And do the same for joystick1 -- convert:</p>
<pre>
for (i = 0; i < joystick1_nbuttons; i++) {
    if (SDL_JoystickGetButton(joystick1, i)) {
        trig1 = 0;
        break;
    }
}
</pre>
<p>to:</p>
<pre>
if (SDL_JoystickGetButton(joystick1, 0))
    trig1 = 0;
</pre>
<p>To map the Rotate Disk function to F11, edit atari_sdl.c:</p>
<p>Add the following into the #include section:</p>
<pre>#include "sio.h"</pre>
<p>Then do a search for "F10", and add the following after the SDLK_F10 case:</p>
<pre>
case SDLK_F11:
    key_pressed = 0;
    SIO_RotateDisks();
    return AKEY_NONE;
</pre>
<p>After making either or both of these changes, run make again, and test.  There's still one more change I'd like to make, but it will have to be at another time.  I like to have the Escape key exit from all of my emulators.  The idea is, any one should be able to run these, and having to remember which function key does what is a pain.  I'll be sure to update this post when I make my change so that you can see how I did it.</p>
<h5>Conclusion:</h5>
<p>Hopefully this guide has been helpful to people interested in RetroGaming on Linux.  Please feel free to share your experiences or issues -- I'm always interested to hear other people's thoughts and ideas.  Have a system you'd like me to cover?  Let me know and I'll do my best to accommodate you.  I enjoy working with all gaming and computer platforms, albeit some of them are not quite as easy to set up.</p>
]]></content:encoded>
			<wfw:commentRss>http://edsalisbury.net/linux-retrogaming-atari-8-bit/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Gaming in Linux</title>
		<link>http://edsalisbury.net/gaming-in-linux/</link>
		<comments>http://edsalisbury.net/gaming-in-linux/#comments</comments>
		<pubDate>Sun, 16 Aug 2009 00:23:14 +0000</pubDate>
		<dc:creator>Ed</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Games]]></category>
		<category><![CDATA[wine]]></category>

		<guid isPermaLink="false">http://www.edsalisbury.net/?p=383</guid>
		<description><![CDATA[<a href="http://edsalisbury.net/gaming-in-linux/" title="Gaming in Linux"></a>One of the reasons people have a hard time making the jump to Linux is the fact that they have a hard time leaving the games they play in Windows. In this article, I&#8217;m going to describe some methods of &#8230;<p class="read-more"><a href="http://edsalisbury.net/gaming-in-linux/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://edsalisbury.net/gaming-in-linux/" title="Gaming in Linux"></a><p><img src="http://www.edsalisbury.net/wp-content/uploads/2009/08/retromenu-150x150.png" alt="Gaming" title="Gaming" width="150" height="150" class="alignleft size-thumbnail wp-image-384" />One of the reasons people have a hard time making the jump to Linux is the fact that they have a hard time leaving the games they play in Windows.  In this article, I&#8217;m going to describe some methods of getting around this hurdle, and make the transition to Linux easier.  I&#8217;m not going to promise that your favorite game will work, but will give you the tools to be able to try.  I&#8217;m also not going to be talking about native linux apps &#8211; those are pretty straightforward.  This article will focus on Windows apps in Linux.<br />
<span id="more-383"></span><br />
The first tool in the linux gamer&#8217;s arsenal is a utility called WINE.  WINE stands for &#8220;Wine Is Not an Emulator&#8221;, in true unix style recursive acronyms.  It&#8217;s job is to make your system look like Windows to your Win apps, giving users the ability to run programs, and for our purposes, games.  The first step to running a windows program in linux is to install WINE (use apt-get / yum to install from the standard repositories), and then simply run &#8216;wine &lt;name of the program.exe&gt;&#8217; &#8211; there&#8217;s a good chance that it will just run.  I have noticed that for some reason game installers tend to be a little temperamental, so one way to get around this is to install on a Windows box and then copy the files to your unix machine over the network.</p>
<p>Another tool is called <a href="http://www.codeweavers.com/products/cxgames/">CrossOver Games</a>, which is a commercially-supported version of WINE.  If you don&#8217;t feel like messing with config files, this may be your best bet.  I haven&#8217;t needed anything but the basic WINE installation, but I&#8217;ve heard good things about this product.</p>
<p>The games that I like are traditionally MMORPGs and emulated games.  I&#8217;ve gotten both Star Wars Galaxies and World of Warcraft running, and Atari800, Stella, and MAME running so far.  Also, I&#8217;ve gotten Spore to run.  I really haven&#8217;t found the need to run much else in the gaming dept, so I&#8217;m set!  The main issues that I&#8217;ve found with running games in linux are:</p>
<ul>
<li>Dual-Screen Issues</li>
<li>Screen Resolution</li>
<li>Keyboard Repeat Issues</li>
</ul>
<h5>Dual-Screen Issues</h5>
<p>First off, I like to do gaming in full screen.  I hate window elements on my game screen.  The issue is when you have a dual monitor set up.  The issue is, Xwindows handles resolutions differently than windows (one big screen vs. 2 smaller screens).  This can be an issue since games will try to use the entire surface, and probably centering the content, making it completely unplayable (half on one screen, half on the other).  In doing some searching, I found a solution to this problem &#8212; it&#8217;s called MetaModes.  Note: I&#8217;m using an Nvidia chipset &#8211; not sure what to do if you&#8217;re using ATI.  To enable MetaModes with TwinView, do the following:</p>
<pre>
# sudo cp /etc/X11/xorg.conf /etc/X11/xorg.conf.backup
# sudo vi /etc/X11/xorg.conf
</pre>
<p>Add the following line in the &#8220;Screen&#8221; Section:</p>
<pre>
Option "metamodes" "1280x1024,1280x1024; 1280x1024,NULL"
</pre>
<p>(This assumes you have 1280&#215;1024 monitors &#8212; change as needed)</p>
<p>Restart your X server &#8212; I usually close all my apps, hit CTRL-ALT-F1, log in, and run:</p>
<pre>
# sudo /etc/init.d/gdm restart
</pre>
<p>This shouldn&#8217;t change anything with your normal desktop, but if you run a fullscreen app, it should only use the first monitor, and turn off the second.  When the app is done, it will go back to the normal 2-screen layout. This setup works pretty well for me.</p>
<h5>Screen Resolutions</h5>
<p>One of the things you&#8217;ll find is that configuration apps written for windows won&#8217;t detect available resolutions correctly when running in Linux.  Since most people run with LCDs lately (which look crap if you don&#8217;t run in the correct resolution), this can be a pain.  Don&#8217;t expect the application to be able to find your ideal resolution.  What I usually do is run the program and let it do it&#8217;s thing with the default res.  Then I quit the program and look for a config file.  Most games have a config file somewhere that states what resolution to run in.  Edit the file manually and re-run the game.  This should fix things so that it runs the way you want.</p>
<h5>Keyboard Repeat Issues</h5>
<p>Lately I&#8217;ve noticed an odd issue with keyboard repeating.  It seems that there is an issue with the latest Xorg version and wine not playing nicely with keyboard repeats.  If you do run into something like this, try disabling keyboard repeating from System->Preferences->Keyboard (in Ubuntu).</p>
<p>One really nice thing about gaming on Linux is the fact that you can keep your software on an NFS mounted filesystem.  If you&#8217;re sharing an installation of WoW, for instance, only one person has to update it, and then it&#8217;s updated for everyone.  It can take a little longer to load from the network, but I haven&#8217;t noticed many issues here.  Another good thing here is the registry.  While I usually try to stay away from games that use the registry, having it in linux is helpful because it&#8217;s not tied to one machine.  You can put it on a remote drive, and it encapsulates the registry so that it could then run on other machines, making it a lot more portable.</p>
]]></content:encoded>
			<wfw:commentRss>http://edsalisbury.net/gaming-in-linux/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to Convert DVDs and TiVo MPEG2 Videos to H.264</title>
		<link>http://edsalisbury.net/how-to-convert-dvds-and-tivo-mpeg2-videos-to-h-264/</link>
		<comments>http://edsalisbury.net/how-to-convert-dvds-and-tivo-mpeg2-videos-to-h-264/#comments</comments>
		<pubDate>Wed, 22 Jul 2009 02:31:52 +0000</pubDate>
		<dc:creator>Ed</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Video]]></category>
		<category><![CDATA[dvd]]></category>
		<category><![CDATA[h.264]]></category>
		<category><![CDATA[mpeg2]]></category>
		<category><![CDATA[TiVo]]></category>

		<guid isPermaLink="false">http://www.edsalisbury.net/?p=353</guid>
		<description><![CDATA[<a href="http://edsalisbury.net/how-to-convert-dvds-and-tivo-mpeg2-videos-to-h-264/" title="How to Convert DVDs and TiVo MPEG2 Videos to H.264"></a>Previously, I have showed you how to set up software to be able to rip DVDs to your hard drive, and I&#8217;ve also shown you how to copy your TiVo videos nightly. I&#8217;ve described the method I use to transcode &#8230;<p class="read-more"><a href="http://edsalisbury.net/how-to-convert-dvds-and-tivo-mpeg2-videos-to-h-264/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://edsalisbury.net/how-to-convert-dvds-and-tivo-mpeg2-videos-to-h-264/" title="How to Convert DVDs and TiVo MPEG2 Videos to H.264"></a><p><img src="http://www.edsalisbury.net/wp-content/uploads/2009/07/Sony-H_264-compress-250-150x150.jpg" alt="H.264" title="H.264" width="150" height="150" class="alignright size-thumbnail wp-image-357" /><br />
Previously, I have showed you how to set up software to be able to <a href="http://www.edsalisbury.net/linux/how-to-rip-dvds-on-ubuntu-linux-9-04-jaunty/">rip DVDs</a> to your hard drive, and I&#8217;ve also shown you how to <a href="http://www.edsalisbury.net/linux/how-to-copy-videos-from-a-series-3-tivo-to-ubuntu-linux/">copy your TiVo videos</a> nightly.  I&#8217;ve described the method I use to <a href="http://www.edsalisbury.net/linux/how-to-convert-tivo-mpeg2-videos-to-h264/">transcode</a> the videos, but haven&#8217;t provided the script&#8230; Until now.  After months of using and tweaking, here&#8217;s what I use.  I call it VidProc.</p>
<p><span id="more-353"></span></p>
<pre class="brush:perl; gutter: false; wrap-lines: true; ruler: false">
#!/usr/bin/perl
# VidProc
# Transcode videos that have been either ripped by ripper or copied from a TiVo
#    to H.264 format
# by Ed Salisbury (ed@edsalisbury.net)
# http://www.edsalisbury.net
# (c)2009 Ed Salisbury, Some Rights Reserved
#
# External Utilities Required:
# * HandBrakeCLI
# * MPlayer/Mencoder
#
# Notes:
# * Settings for HandBrake and mencoder are what I have come up with after
#   doing a fair bit of research, and seem to work pretty well - if you have
#   any concrete suggestions on *better* general-purpose settings, let me know.
#
# License:
# Except where otherwise noted, this work is licensed under Creative Commons
#   Attribution ShareAlike 3.0.
#
# You are free:
#   * to Share -- to copy, distribute and transmit the work
#   * to Remix -- to adapt the work
#
# Under the following conditions:
#   * Attribution. You must attribute the work in the manner specified by the
#     author or licensor (but not in any way that suggests that they endorse
#     you or your use of the work).
#   * Share Alike. If you alter, transform, or build upon this work, you may
#     distribute the resulting work only under the same, similar or a
#     compatible license.
#   * For any reuse or distribution, you must make clear to others the license
#     terms of this work. The best way to do this is with a link to the
#     license's web page (http://creativecommons.org/licenses/by-sa/3.0/)
#   * Any of the above conditions can be waived if you get permission from the
#     copyright holder.
#   * Nothing in this license impairs or restricts the author's moral rights.

use warnings;
use strict;
use File::Copy;
use File::Basename;

sub system_int($);

# Locations
my $DEST = &quot;/path/to/destdir&quot;;
my $QUEUE = &quot;/path/to/queue.txt&quot;;

# Encoding Options
my $DEINT = &quot;pp=md&quot;;    # Deinterlacer
my $VBITRATE = 1000;    # Video Bitrate
my $SAMPLE_RATE = 44.1; # Audio Sample Rate
my $ABITRATE = 192;     # Audio Bitrate
my $OVERSCAN = 6;       # Overscan size (# of lines)

# File Extensions
my $SRC_EXT = &quot;mpg&quot;;
my $DEST_EXT = &quot;mp4&quot;;

# External Utilities
my $HANDBRAKE = &quot;/usr/local/bin/HandBrakeCLI&quot;;
my $MENCODER = &quot;/usr/bin/mencoder&quot;;
my $MPLAYER = &quot;/usr/bin/mplayer&quot;;

# Add backslashes to spaces
$DEST =~ s/ /\ /g;

while (1)
{
    # Read in the queue
    open(QUEUE, $QUEUE);
    my $line = &lt;QUEUE&gt;;
    my @fields;
    if ($line)
    {
        chomp ($line);
        @fields = split(/|/, $line);
    }
    else
    {
        print &quot;Waiting for new stuff to show up in the queue...n&quot;;
        close(QUEUE);
        sleep(60);
        next;
    }
    close (QUEUE);

    my $input = $fields[0];

    print &quot;Processing $inputn&quot;;

    # Fix spaces
    $input =~ s/ /\ /g;
    $input =~ s/'/\'/g;
    $input =~ s/&amp;/\&amp;/g;
    $input =~ s/;/\;/g;
    my @extlist = (&quot;.$SRC_EXT&quot;);

    my $base = basename($input, @extlist);

    if ($fields[1])
    {
        # DVD, since it has a title number
        my $title = $fields[1];
        my $output = &quot;$DEST/${base}_&quot; . $fields[1] . &quot;.$DEST_EXT&quot;;

        system_int(&quot;$HANDBRAKE --input $input --output $output --title $title --turbo --encoder x264 --vb $VBITRATE --audio 1 --aencoder faac --mixdown 6ch --arate $SAMPLE_RATE --ab $ABITRATE --detelecine --decomb --loosePixelratio --markers --two-pass --x264opts ref=3:mixed-refs:bframes=6:weightb:direct=auto:b-pyramid:me=umh:subme=9:analyse=all:8x8dct:trellis=1:nr=150:no-fast-pskip=1:psy-rd=1,1&quot;);
    }
    else
    {
        # TiVo file, since it has no title number
        my $output = &quot;$DEST/${base}.$DEST_EXT&quot;;
        my $line;
        my $width;
        my $height;

        # Get video dimensions
        print &quot;Getting video information... &quot;;
        my @id = `$MPLAYER -nojoystick -nolirc -vo null -ao null -identify -frames 0 $input 2&gt;&amp;1`;
        foreach (@id)
        {
            if (/ID_VIDEO_WIDTH=(d+)/)
            {
                $width = $1;
            }
            if (/ID_VIDEO_HEIGHT=(d+)/)
            {
                $height = $1;
            }
        }
        if (!$width || !$height)
        {
            print &quot;FAILED!&quot;;
        }
        else
        {
            print &quot;(${width}x$height)n&quot;;
        }

        # Crop overscan
        $height-=$OVERSCAN;

        my %croptest;

        # Detect crop region
        print &quot;Detecting crop region... &quot;;
        my @cropdetect = `$MPLAYER -nojoystick -nolirc -vo null -ao null -vf crop=$width:$height:0:$OVERSCAN,cropdetect -ss 600 -endpos 180 $input 2&gt;&amp;1`;
        foreach $line (@cropdetect)
        {
            if ($line =~ /-vf crop=([d:]+)/)
            {
                $croptest{$1}++;
            }
        }

        # Get the crop value with the most hits
        my @croplist = sort { $croptest{$b} &lt;=&gt; $croptest{$a} } keys (%croptest);
        my $crop = $croplist[0];

        if (!$crop)
        {
            print &quot;FAILEDn&quot;;
            exit();
        }
        print &quot;($crop)n&quot;;
        print '-' x 80 . &quot;n&quot;;

        print &quot;Encoding first passn&quot;;
        print '-' x 80 . &quot;n&quot;;
        system_int(&quot;$MENCODER -ovc x264 -x264encopts pass=1:turbo:bitrate=$VBITRATE:bframes=1:me=umh:partitions=all:trellis=1:qp_step=4:qcomp=0.7:direct_pred=auto:keyint=300 -vf $DEINT,crop=$crop,scale=-1:-10,harddup -oac copy -ofps 30000/1001 $input -o /dev/null&quot;);

        print &quot;nn&quot;;
        print '-' x 80 . &quot;n&quot;;
        print &quot;Encoding second passn&quot;;
        print '-' x 80 . &quot;n&quot;;
        system_int(&quot;$MENCODER -ovc x264 -x264encopts pass=2:turbo:bitrate=$VBITRATE:bframes=1:me=umh:partitions=all:trellis=1:qp_step=4:qcomp=0.7:direct_pred=auto:keyint=300 -vf $DEINT,crop=$crop,scale=-1:-10:,harddup -oac copy -ofps 30000/1001 $input -o $output&quot;);
    }
    print &quot;Done. Removing from queuen&quot;;
    print &quot;nn&quot;;
    open(IN, $QUEUE);
    open(OUT, &quot;&gt;$QUEUE.tmp&quot;);
    while (my $qline = &lt;IN&gt;)
    {
        chomp ($qline);
        unless ($line eq $qline)
        {
            print OUT &quot;$qlinen&quot;;
        }
    }
    close (IN);
    close (OUT);
    unlink($QUEUE);
    move(&quot;$QUEUE.tmp&quot;, $QUEUE);
}

# Interruptible System Command
sub system_int($)
{
    my ($cmd) = @_;
    my $pid = fork();
    my $rc;
    if ($pid == 0)
    {
        exec($cmd);
    }
    else
    {
        waitpid($pid,0);
        $rc = $?;
    }
    return $rc;
}
</pre>
<p>It uses the same queue file that the other scripts will write to, so think of this as a continuation of the previous articles.  To use it, stick it somewhere like /usr/local/bin, and then change the locations to be wherever your queue is, and where you want your videos to end up.  The transcoding settings can get a little hairy, so I would say don&#8217;t mess with the actual command lines unless you know what you&#8217;re doing (but, if you did, you probably wouldn&#8217;t need this script!)</p>
<h4>External Utilities Needed:</h4>
<p>HandBrakeCLI &#8211; this can be downloaded from <a href="http://handbrake.fr/?article=download">here</a><br />
mplayer/mencoder &#8211; This can be installed via apt-get</p>
<h4>A couple of Notes/FAQs:</h4>
<p><b>Overscan removal:</b><br />
If you deal with letterboxed videos copied from TV, you&#8217;ll know what a pain overscan can be &#8211; Overscan is the generic term for the fuzzy line above the video that gets really annoying when watching on your monitor, but not on your TV.  This can wreak havoc with detecting where to crop the video, so I remove it.</p>
<p><b>HandBrake *AND* mencoder??  Why?</b><br />
I found that for some reason, Handbrake didn&#8217;t like working with the files that were copied from the TiVo &#8211; I dealt with lots of weird sync issues.  I posted it on the Handbrake forum, but never got a solution.  I ended up just using mencoder for the TiVo files, and Handbrake for the DVD rips, and left it at that.</p>
<p><b>Your setting XXX sucks &#8211; you should use YYY!</b><br />
If you can state that for any type of program (animation, TV, letterboxed, HD, etc.) that this is correct (and that it doesn&#8217;t make the process take much longer), I&#8217;ll happily thank you and update the script (as well as give you a mention here.)  I spent a bit of time trying to find settings that would work well for what I wanted, and ended up choosing these.  They&#8217;re not going to have the <b>best</b> quality, but the size and the time to transcode were good, so that&#8217;s what I stuck with.</p>
]]></content:encoded>
			<wfw:commentRss>http://edsalisbury.net/how-to-convert-dvds-and-tivo-mpeg2-videos-to-h-264/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>How to Copy Videos from a Series 3 TiVo to Ubuntu Linux</title>
		<link>http://edsalisbury.net/how-to-copy-videos-from-a-series-3-tivo-to-ubuntu-linux/</link>
		<comments>http://edsalisbury.net/how-to-copy-videos-from-a-series-3-tivo-to-ubuntu-linux/#comments</comments>
		<pubDate>Sat, 18 Jul 2009 05:27:19 +0000</pubDate>
		<dc:creator>Ed</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Video]]></category>

		<guid isPermaLink="false">http://www.edsalisbury.net/?p=341</guid>
		<description><![CDATA[<a href="http://edsalisbury.net/how-to-copy-videos-from-a-series-3-tivo-to-ubuntu-linux/" title="How to Copy Videos from a Series 3 TiVo to Ubuntu Linux"></a>This guide will show you how to set up a script to copy programs from your Series 3 TiVo on a regular basis, without having to do a thing after it&#8217;s set up! Information you will need: Your TiVo&#8217;s IP &#8230;<p class="read-more"><a href="http://edsalisbury.net/how-to-copy-videos-from-a-series-3-tivo-to-ubuntu-linux/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://edsalisbury.net/how-to-copy-videos-from-a-series-3-tivo-to-ubuntu-linux/" title="How to Copy Videos from a Series 3 TiVo to Ubuntu Linux"></a><p><img src="http://www.edsalisbury.net/wp-content/uploads/2009/07/tivo-logo1-134x150.jpg" alt="TiVo" title="TiVo" width="134" height="150" class="alignleft size-thumbnail wp-image-298" /><br />
This guide will show you how to set up a script to copy programs from your Series 3 TiVo on a regular basis, without having to do a thing after it&#8217;s set up!</p>
<p>Information you will need:</p>
<ul>
<li>Your TiVo&#8217;s IP Address (needs to be static)</li>
<li>Your TiVo&#8217;s Media Access Key (MAK) &#8211; this can be found on tivo.com after you&#8217;ve logged in</li>
<li>The location where you want your files to be dumped (they are *big* &#8211; figure 1 GB per hour for SD, and like 5 GB per hour for HD)</li>
<li>The location where the files will eventually be stored</li>
</ul>
<p><span id="more-341"></span></p>
<p>The external utilities you will need:</p>
<ul>
<li>Curl &#8211; Install via <code>sudo apt-get install curl</code></li>
<li>Tivodecode &#8211; download from <a href="http://sourceforge.net/projects/tivodecode/files/">Sourceforge</a></li>
</ul>
<p>You will also need to install the following <a href="http://www.edsalisbury.net/linux/installing-perl-modules-on-ubuntu/">CPAN</a> perl modules:</p>
<ul>
<li>Net::TiVo</li>
<li>XML::Simple</li>
<li>Text::Unidecode</li>
</ul>
<p>After you have all of that stuff installed and info gathered, it&#8217;s time to install my tivo_dump script:</p>
<pre class="brush:perl; gutter: false; wrap-lines: true; ruler: false">
#!/usr/bin/perl
# TiVo Dump
# Copy TiVo programs from a Series3 TiVo
# by Ed Salisbury (ed@edsalisbury.net)
# http://www.edsalisbury.net
# (c)2009 Ed Salisbury, Some Rights Reserved
#
# External Utilities Required:
# * curl
# * tivodecode
#
# External Perl Modules Required:
# * Net::TiVo
# * XML::Simple
# * Text::Unidecode;
#
# Usage:
# tivo_dump
#
# License:
# Except where otherwise noted, this work is licensed under Creative Commons
#   Attribution ShareAlike 3.0.
#
# You are free:
#   * to Share - to copy, distribute and transmit the work
#   * to Remix - to adapt the work
#
# Under the following conditions:
#   * Attribution. You must attribute the work in the manner specified by the
#     author or licensor (but not in any way that suggests that they endorse
#     you or your use of the work).
#   * Share Alike. If you alter, transform, or build upon this work, you may
#     distribute the resulting work only under the same, similar or a
#     compatible license.
#   * For any reuse or distribution, you must make clear to others the license
#     terms of this work. The best way to do this is with a link to the
#     license's web page (http://creativecommons.org/licenses/by-sa/3.0/)
#   * Any of the above conditions can be waived if you get permission from the
#     copyright holder.
#   * Nothing in this license impairs or restricts the author's moral rights.

use warnings;
use strict;
use Net::TiVo;
use XML::Simple;
use utf8;
use Text::Unidecode;

sub fix_chars($);

# User-Configurable Variables
my $HOST = &quot;&quot;;      # Hostname/IP of the TiVo
my $MAK = &quot;&quot;;       # The Media Access Key of the TiVo
my $VIDEO_DIR = &quot;&quot;; # Where the programs get saved
my $COPY_SUGGESTIONS = 0; # If you want to copy &quot;Suggested&quot; programs, set this to 1

my $USER = &quot;tivo&quot;;
my $TMPFILE = &quot;/tmp/$$.xml&quot;;
my $PROGRAMS_FILE = &quot;/home/username/.tivo_programs&quot;;
$|++;

# External Utilities
my $CURL = &quot;/usr/bin/curl&quot;;
my $TIVODECODE = &quot;/usr/local/bin/tivodecode&quot;;

my @PREV;

# Connect to the TiVo
print &quot;Connecting to TiVo at $HOST... &quot;;
my $tivo = Net::TiVo-&gt;new(host =&gt; $HOST, mac =&gt; $MAK);
my @folders = $tivo-&gt;folders();
if (@folders)
{
    print &quot;OKn&quot;;
}
else
{
    print &quot;FAILn&quot;;
    exit();
}

# Load the file that has the previously saved programs
open(IN, $PROGRAMS_FILE);
while (&lt;IN&gt;)
{
    chop();
    push(@PREV, $_);
}
close (IN);

# Go through each folder on the TiVo
foreach my $folder (@folders)
{
    foreach my $item ($folder-&gt;{'xmlref'}{'Item'})
    {
        foreach my $video (@$item)
        {
            # Only process videos, not folders
            if ($video-&gt;{'Links'}{'Content'}{'ContentType'} eq &quot;video/x-tivo-raw-tts&quot;)
            {
                # Choose video type based on the icon
                if ($video-&gt;{'Links'}{'CustomIcon'} &amp;&amp; $video-&gt;{'Links'}{'CustomIcon'}{'Url'} eq &quot;urn:tivo:image:suggestion-recording&quot; &amp;&amp; !$COPY_SUGGESTIONS)
                {
                    next;
                }
                if ($video-&gt;{'Links'}{'CustomIcon'} &amp;&amp;
                   ($video-&gt;{'Links'}{'CustomIcon'}{'Url'} eq &quot;urn:tivo:image:in-progress-transfer&quot; ||
                    $video-&gt;{'Links'}{'CustomIcon'}{'Url'} eq &quot;urn:tivo:image:in-progress-recording&quot;))
                {
                   next;
                }

                # Get program and episode titles
                my $program_title = $video-&gt;{'Details'}{'Title'};

                if ($video-&gt;{'Details'}{'EpisodeTitle'})
                {
                    $program_title .= &quot; - &quot; . $video-&gt;{'Details'}{'EpisodeTitle'};
                }

                # Get Program ID and Video URL
                my $video_url = $video-&gt;{'Links'}{'Content'}{'Url'};
                my $program_id = $video-&gt;{'Details'}{'ProgramId'};

                if (!$program_id)
                {
                    next;
                }

                # If previously copied, skip
                if (grep /^$program_id$/, @PREV)
                {
                    print &quot;Skipping $program_title.n&quot;;
                    next;
                }

                # get details XML file
                print &quot;Getting details for $program_title... &quot;;
                my $details_xml = $video-&gt;{'Links'}{'TiVoVideoDetails'}{'Url'};

                system(&quot;$CURL --digest -s -k -u $USER:$MAK -c /tmp/cookies.txt -o $TMPFILE &quot;$details_xml&quot;&quot;);
                if (-f $TMPFILE)
                {
                    print &quot;OKnProcessing details file... &quot;;
                    my $xml = XML::Simple-&gt;new();
                    my $doc = $xml-&gt;XMLin($TMPFILE);
                    my %meta;
                    my $filepath;
                    my $filename;

                    # Get rating and convert to proper form
                    $meta{'tvRating'} = $doc-&gt;{'showing'}{'tvRating'}{'content'};
                    if ($meta{'tvRating'})
                    {
                        if ($meta{'tvRating'} eq &quot;Y_7&quot;) { $meta{'tvRating'} = 'x1'; }
                        elsif ($meta{'tvRating'} eq &quot;PG&quot;) { $meta{'tvRating'} = 'x4'; }
                        elsif ($meta{'tvRating'} eq &quot;_14&quot;) { $meta{'tvRating'} = 'x5'; }
                        else { $meta{'tvRating'} = &quot;x7&quot;; }
                    }

                    # Get other data
                    $meta{'vActor'} = $doc-&gt;{'showing'}{'program'}{'vActor'}{'element'};
                    $meta{'vDirector'} = $doc-&gt;{'showing'}{'program'}{'vDirector'}{'element'};
                    $meta{'vProgramGenre'} = $doc-&gt;{'showing'}{'program'}{'vProgramGenre'}{'element'};
                    $meta{'vSeriesGenre'} = $doc-&gt;{'showing'}{'program'}{'series'}{'vSeriesGenre'}{'element'};
                    $meta{'seriesTitle'} = $doc-&gt;{'showing'}{'program'}{'series'}{'seriesTitle'};
                    $meta{'title'} = $doc-&gt;{'showing'}{'program'}{'title'};
                    $meta{'isEpisode'} = $doc-&gt;{'showing'}{'program'}{'isEpisode'};
                    $meta{'originalAirDate'} = $doc-&gt;{'showing'}{'program'}{'originalAirDate'};
                    $meta{'episodeTitle'} = $doc-&gt;{'showing'}{'program'}{'episodeTitle'};
                    $meta{'description'} = $doc-&gt;{'showing'}{'program'}{'description'};

                    if (defined $meta{'description'})
                    {
                        $meta{'description'} =~ s/s+Copyright.*$//;
                    }

                    # Process Titles

                    $meta{'episodeNumber'} = $doc-&gt;{'showing'}{'program'}{'episodeNumber'};

                    my $series_title = '';
                    my $episode_number = '';
                    my $episode_title = '';
                    my $title = '';

                    if ($meta{'seriesTitle'})
                    {
                        $series_title = fix_chars($meta{'seriesTitle'});
                    }
                    if ($meta{'episodeNumber'})
                    {
                        $episode_number = fix_chars($meta{'episodeNumber'});
                    }
                    if ($meta{'episodeTitle'})
                    {
                        $episode_title = fix_chars($meta{'episodeTitle'});
                    }
                    if ($meta{'title'})
                    {
                        $title = fix_chars($meta{'title'});
                    }

                    if ($series_title &amp;&amp; $episode_number &amp;&amp; $episode_title)
                    {
                        $filepath = &quot;$VIDEO_DIR/$series_title&quot;;
                        $filename = &quot;$filepath/$series_title - $episode_number - $episode_title&quot;;
                    }
                    elsif ($series_title &amp;&amp; $episode_title)
                    {
                        $filepath = &quot;$VIDEO_DIR/$series_title&quot;;
                        $filename = &quot;$filepath/$series_title - $episode_title&quot;;
                    }
                    elsif ($title)
                    {
                        $filepath = &quot;$VIDEO_DIR/$title&quot;;
                        $filename = &quot;$filepath/$title&quot;;
                    }
                    else
                    {
                        $filepath = &quot;$VIDEO_DIR&quot;;
                        $filename = &quot;$filepath/Unknown&quot;;
                    }
                    print &quot;OKn&quot;;

                    unless (-d $filepath)
                    {
                        print &quot;Path $filepath doesn't exist, creating... &quot;;
                        mkdir($filepath);
                        if (-d $filepath)
                        {
                            print &quot;OKn&quot;;
                        }
                        else
                        {
                            print &quot;FAILn&quot;;
                            exit;
                        }
                    }

                    # Get the video with curl
                    print &quot;Getting video... &quot;;
                    system(&quot;$CURL --digest -s -k -u $USER:$MAK -c /tmp/cookies.txt -o &quot;$filename.tivo&quot; &quot;$video_url&quot;&quot;);
                    if (-f &quot;$filename.tivo&quot;)
                    {
                        my $filesize = (stat(&quot;$filename.tivo&quot;))[7];

                        if ($filesize &gt; 0)
                        {
                            print &quot;OKn&quot;;

                            # Convert to MPG
                            print &quot;Converting video to MPG format... &quot;;
                            system(&quot;$TIVODECODE -m $MAK -o &quot;$filename.mpg&quot; &quot;$filename.tivo&quot; &gt; /dev/null 2&gt;&amp;1&quot;);
                            if (-f &quot;$filename.mpg&quot;)
                            {
                                print &quot;OKn&quot;;
                                unlink &quot;$filename.tivo&quot;;
                                open(OUT, &quot;&gt;&gt;$PROGRAMS_FILE&quot;);
                                print OUT &quot;$program_idn&quot;;
                                close(OUT);
                            }
                            else
                            {
                                print &quot;FAILn&quot;;
                                exit();
                            }

                            # Output metadata file
                            print &quot;Outputting metadata... &quot;;
                            open (OUT, &quot;&gt;$filename.mpg.txt&quot;);

                            foreach my $key (keys %meta)
                            {
                                if ($meta{$key})
                                {
                                    if ($meta{$key} =~ /^ARRAY/)
                                    {
                                        foreach my $item (@{$meta{$key}})
                                        {
                                            unless ($item =~ /^HASH/)
                                            {
                                                print OUT &quot;$key : &quot; . fix_chars($item) . &quot;n&quot;;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        unless ($item =~ /^HASH/)
                                        {
                                            if ($key eq &quot;originalAirDate&quot;)
                                            {
                                                print OUT &quot;$key : &quot; . $meta{$key} . &quot;n&quot;;
                                            }
                                            else
                                            {
                                                print OUT &quot;$key : &quot; . fix_chars($meta{$key}) . &quot;n&quot;;
                                            }
                                        }
                                    }
                                }
                            }
                            unlink($TMPFILE);
                            close(OUT);
                            print &quot;OKn&quot;;
                        }
                        else
                        {
                            print &quot;FAILn&quot;;
                        }
                    }
                    else
                    {
                        print &quot;FAILn&quot;;
                        exit();
                    }
                }
                else
                {
                    print &quot;FAILn&quot;;
                    exit();
                }
            }
        }
    }
}

# Convert any offending characters
sub fix_chars($)
{
    my ($data) = @_;

    $data = unidecode($data);

    $data =~ s/:/ -/g;
    $data =~ s///-/g;
    $data =~ s/\/-/g;
    $data =~ s/?/-/g;
    $data =~ s/*/-/g;

    return $data;
}
</pre>
<p>Put the script wherever you want it &#8211; (I usually put my scripts into /usr/local/bin) &#8211; Edit the script, and fill in the $HOST, $MAK, and $VIDEO_DIR variables with the data gathered in step 1.  Then do a test run.  It will take a while to copy the data.  If it&#8217;s working fine, add to cron to have it copy the files regularly.  I copy mine at midnight:</p>
<p><code>0 0 * * * /usr/local/bin/tivo_dump >/dev/null 2>&#038;1</code></p>
<p>This says, run every day at midnight and send the output to /dev/null (otherwise you&#8217;ll get emails every day, which you may or may not want). </p>
<p>Note: Most of this script deals with metadata &#8211; it writes a text file (filename).txt with the metadata about the program, which is in pyTivo format.  For more info, see my <a href="http://www.edsalisbury.net/linux/how-to-set-up-a-tivo-media-server-on-ubuntu-linux/">guide</a> on how to set up pyTivo as a media server for TiVos.</p>
]]></content:encoded>
			<wfw:commentRss>http://edsalisbury.net/how-to-copy-videos-from-a-series-3-tivo-to-ubuntu-linux/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Installing Perl Modules on Ubuntu Linux</title>
		<link>http://edsalisbury.net/installing-perl-modules-on-ubuntu/</link>
		<comments>http://edsalisbury.net/installing-perl-modules-on-ubuntu/#comments</comments>
		<pubDate>Wed, 08 Jul 2009 14:00:02 +0000</pubDate>
		<dc:creator>Ed</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[cpan]]></category>
		<category><![CDATA[perl]]></category>

		<guid isPermaLink="false">http://www.edsfamily.com/ed/archives/10</guid>
		<description><![CDATA[<a href="http://edsalisbury.net/installing-perl-modules-on-ubuntu/" title="Installing Perl Modules on Ubuntu Linux"></a>I&#8217;ve been a perl programmer/scripter/hacker for many years now, and I will frequently use CPAN modules to be able to do the out-of-the ordinary. This small guide is intended to help people easily install these modules. First, let&#8217;s get the &#8230;<p class="read-more"><a href="http://edsalisbury.net/installing-perl-modules-on-ubuntu/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://edsalisbury.net/installing-perl-modules-on-ubuntu/" title="Installing Perl Modules on Ubuntu Linux"></a><p><img src="http://www.edsalisbury.net/wp-content/uploads/2007/12/perl_image-138x150.jpg" alt="perl" title="perl" width="138" height="150" class="alignright size-thumbnail wp-image-319" /><br />
I&#8217;ve been a perl programmer/scripter/hacker for many years now, and I will frequently use <a href="http://www.cpan.org/">CPAN</a> modules to be able to do the out-of-the ordinary.  This small guide is intended to help people easily install these modules.</p>
<p>First, let&#8217;s get the CPAN module up to date:</p>
<p><code>$ sudo perl -MCPAN -e shell</code><br />
(take defaults to set everything up)<br />
<code>cpan&gt; exit</code><br />
<code>$ sudo perl -MCPAN -e shell<br />
cpan&gt; install Bundle::CPAN</code><br />
(answer yes to the question about saving data)<br />
<code>cpan&gt; reload cpan</code></p>
<p>Then, to install a module, it&#8217;s simply:<br />
<code>$ sudo perl -MCPAN -e shell<br />
cpan&gt; install &lt;name of module&gt;</code><br />
<code>cpan&gt; exit</code></p>
]]></content:encoded>
			<wfw:commentRss>http://edsalisbury.net/installing-perl-modules-on-ubuntu/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Asynchronous Mirroring in Unix</title>
		<link>http://edsalisbury.net/asynchronous-mirroring-in-unix/</link>
		<comments>http://edsalisbury.net/asynchronous-mirroring-in-unix/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 14:00:11 +0000</pubDate>
		<dc:creator>Ed</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[mirroring]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://www.edsalisbury.net/?p=306</guid>
		<description><![CDATA[<a href="http://edsalisbury.net/asynchronous-mirroring-in-unix/" title="Asynchronous Mirroring in Unix"></a>One of the issues I&#8217;ve found with having lots of data is the fact that I&#8217;m worried that a hard drive will fail, and I&#8217;ll lose something important. Since I did have that happen earlier this year, I am now &#8230;<p class="read-more"><a href="http://edsalisbury.net/asynchronous-mirroring-in-unix/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://edsalisbury.net/asynchronous-mirroring-in-unix/" title="Asynchronous Mirroring in Unix"></a><p><img src="http://www.edsalisbury.net/wp-content/uploads/2009/07/unix-150x150.jpg" alt="Un*x" title="Un*x" width="150" height="150" class="alignleft size-thumbnail wp-image-308" /><br />
One of the issues I&#8217;ve found with having lots of data is the fact that I&#8217;m worried that a hard drive will fail, and I&#8217;ll lose something important.  Since I did have that happen earlier this year, I am now determined to not let it happen again.  I&#8217;ve been focusing a lot on resiliency &#8211; making it so that there are no single points of failure.  Since I have been collecting a lot of hard drives, I decided to put them to good use, and set up some data replication onto multiple drives.</p>
<p>You might ask, why not just set up a RAID5?  Or, alternatively, why not buy a Drobo and be done with it?  I hear the first one a lot, especially since I deal with RAID day in and day out for my day job.  The main issue I don&#8217;t do either of these things is that I&#8217;m cheap!  I want to be able to use all of the hardware I have without tossing out old stuff.  On my server, I have the following drives:</p>
<p><span id="more-306"></span></p>
<ul>
<li>disk1: 120 GB ATA</li>
<li>disk2: 200 GB ATA</li>
<li>disk3: 300 GB USB</li>
<li>disk4: 400 GB Firewire</li>
<li>disk5: 600 GB SATA</li>
<li>disk6: 1000 GB USB</li>
<li>disk7: 1500 GB USB</li>
</ul>
<p>Try to set up a RAID with all of that!  The problem with this is the disparate drive sizes (RAID requires disks to be the same size, and will use the lowest common denominator if not.)  I&#8217;ve been &#8216;collecting&#8217; hard drives for quite a while, and I like the fact that I can just go to the local electronics store and pick up another drive when I run out of space.  This configuration does have a downside though, and that is, how do you decide where to put everything?  I decided to sit down and figure out how much space I actually need for each of my data types, and came up with this list (taking approximate growth rates into consideration):</p>
<ul>
<li>Photos: 100 GB</li>
<li>Music: 300 GB</li>
<li>Movies: 1 TB</li>
<li>TV: 400 GB</li>
<li>Software: 150 GB</li>
</ul>
<p>I then tried to map things out onto the drives I have:</p>
<ul>
<li>disk1: Photos</li>
<li>disk2: Software</li>
<li>disk3: Music</li>
<li>disk4: TV</li>
<li>disk6: Movies</li>
</ul>
<p>This leaves two disks, disk5 (600 GB) and disk7 (1500 GB) left to be able to mirror to.  Since I can&#8217;t use standard mirroring software, I&#8217;m not able to have a real-time mirror.  This is OK for my purposes, as I don&#8217;t intend on having them be hot-swappable, etc. &#8212; I just want another copy of my data out there, without having to worry about making backups all the time.</p>
<p>I set up my server to only export the data disks (I don&#8217;t want to be able to write to the backups from my desktop, as the changes will be overwritten by the backups)  I also set up my filesystem in a convenient manner &#8212; everything is a directory off of /data:</p>
<ul>
<li>/data/Photos</li>
<li>/data/Video</li>
<li>/data/Software</li>
<li>/data/Audio</li>
</ul>
<p>This makes it very easy to get to any of my data  (try that in Windows!)</p>
<p>One inherent advantage of having an asynchronous mirror is the fact that it can serve as a temporary backup if you accidentally delete a file/directory, whereas with a normal mirror, you&#8217;d still have to back up to tape or some other drive to be able to get this data back.</p>
<p>To do the actual mirroring, I opted to create a simple rsync script that will copy the data nightly from cron.  Nothing overly complex, but something that makes it easy to add new filesystems via a config file:</p>
<pre class="brush:perl; gutter: false; wrap-lines: true; ruler: false">
#!/usr/bin/perl
# Mirror
# Asynchronously mirror filesystems on a local machine
# by Ed Salisbury (ed@edsalisbury.net)
# http://www.edsalisbury.net
# (c)2009 Ed Salisbury, Some Rights Reserved
#
# External Utilities Required:
# * rsync
#
# License:
# Except where otherwise noted, this work is licensed under Creative Commons
#   Attribution ShareAlike 3.0.
#
# You are free:
#   * to Share — to copy, distribute and transmit the work
#   * to Remix — to adapt the work
#
# Under the following conditions:
#   * Attribution. You must attribute the work in the manner specified by the
#     author or licensor (but not in any way that suggests that they endorse
#     you or your use of the work).
#   * Share Alike. If you alter, transform, or build upon this work, you may
#     distribute the resulting work only under the same, similar or a
#     compatible license.
#   * For any reuse or distribution, you must make clear to others the license
#     terms of this work. The best way to do this is with a link to the
#     license's web page (http://creativecommons.org/licenses/by-sa/3.0/)
#   * Any of the above conditions can be waived if you get permission from the
#     copyright holder.
#   * Nothing in this license impairs or restricts the author's moral rights.

use warnings;
use strict;

# Configuration file for mirrors
# Example Config:
# /data/Photos/       /backup/Backup/Photos/
# /data/Software/     /backup/Backup/Software/
# /data/Audio/        /backup/Backup/Audio/
# /data/Video/        /backup/Backup/Video/
# /data/Misc/         /backup/Backup/Misc/
my $CONFIG = "/usr/local/etc/mirror.cfg";

open(CFG, $CONFIG);
my @lines = &lt;CFG&gt;;
close(CFG);

foreach my $line (@lines)
{
    my ($src, $dest) = split(/s+/, $line);
    system("/usr/bin/rsync -av --delete $src $dest");
}
</pre>
<p>I put this script into /usr/local/bin, and then created a config file /usr/local/etc/mirror.conf similar to this:</p>
<pre>
/data/Photos/       /backup/Backup/Photos/
/data/Software/     /backup/Backup/Software/
/data/Audio/        /backup/Backup/Audio/
/data/Video/        /backup/Backup/Video/
/data/Misc/         /backup/Backup/Misc/
</pre>
<p>I then added a cronjob to have it run nightly:</p>
<pre>0 0 * * * /bin/backup > /dev/null 2>&#038;1</pre>
<p><strong><br />
A word of caution: Make *sure* you have the directories right!  rsync is set up to *DELETE* files in the destination if the file isn&#8217;t in the source directory, so if you have it rsync to two different directories, it will delete files as needed in the destination to sync them up.  You have been warned!  I take no responsibility for you deleting your data!</strong></p>
<p>Please let me know if you found this guide/script useful.</p>
]]></content:encoded>
			<wfw:commentRss>http://edsalisbury.net/asynchronous-mirroring-in-unix/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How to Set Up a TiVo Media Server on Ubuntu Linux</title>
		<link>http://edsalisbury.net/how-to-set-up-a-tivo-media-server-on-ubuntu-linux/</link>
		<comments>http://edsalisbury.net/how-to-set-up-a-tivo-media-server-on-ubuntu-linux/#comments</comments>
		<pubDate>Fri, 03 Jul 2009 20:40:40 +0000</pubDate>
		<dc:creator>Ed</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Video]]></category>
		<category><![CDATA[pytivo]]></category>
		<category><![CDATA[TiVo]]></category>

		<guid isPermaLink="false">http://www.edsfamily.com/ed/?p=97</guid>
		<description><![CDATA[<a href="http://edsalisbury.net/how-to-set-up-a-tivo-media-server-on-ubuntu-linux/" title="How to Set Up a TiVo Media Server on Ubuntu Linux"></a>This guide will help you set up a media server to be able to play videos on your Series 3 TiVo, using pyTiVo. (Note: this post was moved from my old blog, but has been updated a bit) First, install &#8230;<p class="read-more"><a href="http://edsalisbury.net/how-to-set-up-a-tivo-media-server-on-ubuntu-linux/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<a href="http://edsalisbury.net/how-to-set-up-a-tivo-media-server-on-ubuntu-linux/" title="How to Set Up a TiVo Media Server on Ubuntu Linux"></a><p><img src="http://www.edsalisbury.net/wp-content/uploads/2009/07/tivo-logo1-134x150.jpg" alt="TiVo" title="TiVo" width="134" height="150" class="alignright size-thumbnail wp-image-298" /><br />
This guide will help you set up a media server to be able to play videos on your Series 3 TiVo, using pyTiVo.  (Note: this post was moved from my old blog, but has been updated a bit)</p>
<p>First, install ffmpeg:</p>
<pre>$ sudo apt-get install ffmpeg</pre>
<p>Then, install git (needed to grab pyTivo):</p>
<pre>$ sudo apt-get install git-core</pre>
<p>Then, grab the latest version of the pyTivo script (Look at the <a href="http://pytivo.armooo.net/wiki/CurrentRelease">Current Release</a> page to verify that you have the right version):</p>
<pre>$ cd /usr/share
$ sudo git clone git://repo.or.cz/pyTivo/wmcbrine.git
$ sudo mv wmcbrine pyTivo</pre>
<p>Edit /usr/share/pyTivo/pyTivo.conf:</p>
<pre>$ cd /usr/share/pyTivo
$ sudo cp pyTivo.conf.dist pyTivo.conf
$ sudo vi pyTivo.conf</pre>
<p>The only thing that I changed is to comment out the default video share, and add my own:</p>
<pre>[Movies]
type=video
path=/data/Video/Movies
[Television]
type=video
path=/data/Video/Television
[Music]
type=music
path=/data/Audio/Music</pre>
<p>Run pyTivo:</p>
<pre>$ sudo python /usr/share/pyTivo/pyTivo.py</pre>
<p>Verify that things are working correctly &#8212; on the Tivo, go to &#8220;Now Playing List&#8221; and look for the shares.  If they appear and you can browse to them, you&#8217;re almost done!</p>
<p>One issue I had was with transferring the videos.  When I transferred them to the TiVo, it had a message of &#8220;unknown mpeg2 codec&#8221; or something to that effect.  Apparently the package for ffmpeg on Intrepid doesn&#8217;t have all of the codecs needed.  To install them, run the following:</p>
<pre>$ sudo apt-get install libavcodec-unstripped-51</pre>
<p>After I did this, videos were able to be transferred just fine.</p>
<p>The last thing to do is to make pyTiVo start automatically on bootup.  To do this, simply copy the following script to /etc/init.d:</p>
<pre class="brush:bash; gutter: false; wrap-lines: true; ruler: false">
#!/bin/bash
# chkconfig: 2345 99 05
# description: pyTivo server

### INIT INFO
# Provides: pytivo
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-description: pyTivo server
# Description: Start and stop the pyTivo server.
### END INIT INFO

RETVAL=0

start() {
echo -n "Starting pyTivo: "
pgrep -f pyTivo.py
RETVAL=$?
[ $RETVAL -eq 0 ] &#038;&#038; echo "pyTivo already running: Exiting" &#038;&#038; exit 1

# this call actually starts pyTivo.
python /usr/share/pyTivo/pyTivo.py > /dev/null 2>&#038;1 &#038;
RETVAL=$?
[ $RETVAL -eq 0 ] &#038;&#038; echo -n "done"
echo
return $RETVAL
}

stop() {
echo -n "Stopping pyTivo: "
pkill -f pyTivo.py
RETVAL=$?
echo
[ $RETVAL -eq 0 ] &#038;&#038; echo -n "done"
echo
return $RETVAL
}

# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
stop
sleep 1
start
RETVAL=$?
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit $RETVAL
</pre>
<p><em>Note: I didn&#8217;t write this &#8211; I just grabbed it from somewhere when setting it up &#8211; let me know if you wrote it so that I can give you credit!</em></p>
<p>After creating the script, make it executable:</p>
<pre>$ sudo chmod u+x /etc/init.d/pytivo</pre>
<p>Then create links to /etc/rc3.d and /etc/rc1.d:</p>
<pre>$ sudo ln -s /etc/init.d/pytivo /etc/rc3.d/S99pytivo
$ sudo ln -s /etc/init.d/pytivo /etc/rc1.d/K99pytivo
</pre>
<p>This should make it so that pytivo starts automatically upon bootup.</p>
<p>Hopefully you&#8217;ve found this guide useful.  Next time, I&#8217;ll be talking about how to make the videos show up perfectly on the TiVo, with appropriate titles, etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://edsalisbury.net/how-to-set-up-a-tivo-media-server-on-ubuntu-linux/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
	</channel>
</rss>

