Wednesday, December 3, 2008

Capture a radio stream into a podcast

I like the radio show "Morning Becomes Eclectic" on KCRW so I came up with a Perl script to capture the internet stream of the show, add tags to it, add bookmarks to it (so I can skip through songs I don't like by double-clicking my iPhone headphones), and making it a podcast so iTunes and my iPod and iPhone can download new "episodes" when they become available.

KCRW is a great radio station so if you do listen to them you should consider a donation.

Here is the Perl script. It requires one argument, the number of minutes you want to record. Change "username" to your user name. It also requires the programs mplayer, ffmpeg, and Apple's ChapterTool (which you can find on the internet or buried inside GarageBand). Start the built-in webserver and then subscribe to the RSS feed that gets created there using iTunes (/Users/username/Sites/ripper.xml).




#!/usr/bin/perl -w

use XML::Writer;
use IO::File;
use File::Copy;
use XML::RSS;


# get date
use POSIX qw(strftime);
$now = strftime "%b_%d_%Y", localtime;

# let's rock'n roll
my $duration = $ARGV[0];
my $tmp = "/tmp/";
#my $datestamp = `date +%s`;
my $fifo = $tmp."fifo_".$now."\.mp3";
print $fifo;
`mkfifo $fifo`;


# run mplayer and ffmpeg in the background
system("ffmpeg -i $fifo -acodec aac -b 1200 /tmp/eclectic_$now.m4a &");
my $pid = fork();
if (not defined $pid) {
warn "resources not avilable.\n";
} elsif ($pid == 0) {
exec("mplayer -quiet -playlist http://media.kcrw.com/live/kcrwlive.pls -ao pcm:file=$fifo -vc dummy -vo null -ac ffmp3");
exit(0);
print "right after exec gets called\n";
}

# wait the specified time and then kill mplayer
sleep($duration * 60);
kill 2, $pid;
waitpid($pid,0);

# get the length of the file
my $length = `mplayer -vo null -ao null -frames 0 -identify /tmp/eclectic_$now.m4a 2>/dev/null | grep -v "=0" | grep "^ID_LENGTH" | uniq | cut -d"=" -f2`;
chomp($length);
$length = $length / 60;
$length = sprintf("%d", $length);

my $output = new IO::File(">/tmp/output.xml");
my $writer = new XML::Writer(OUTPUT => $output, NEWLINES => 1);
$writer->xmlDecl("UTF-8");
$writer->startTag("chapters", "version" => "1");
$i = 0;
while ($i < ($length+1)){
$writer->startTag("chapter", "starttime" => $i.":00");
$writer->startTag("title");
my $chapter = $i+1;
$writer->characters("Chapter ".$chapter);
$writer->endTag("title");
$writer->endTag("chapter");
$i++;
}
$writer->endTag("chapters");
$writer->end();
$output->close();


# add chapters
print "adding chapters...\n";
`ChapterTool -x /tmp/output.xml -a /tmp/eclectic_$now.m4a -o /tmp/eclectic_$now.m4b`;

#rm -rf $FIFO
#rm /tmp/eclectic_$NOW.m4a

## add tags
print "adding tags...\n";
`AtomicParsley /tmp/eclectic_$now.m4b --overWrite --artist "Morning Becomes Eclectic" --title "MBE- $now" --album "Morning Becomes Eclectic" --artwork /Users/username/Sites/nic_harcourt.jpg`;

# move to web site
print "moving to website directory...\n";
move("/tmp/eclectic_$now.m4b","/Users/username/Sites/") or die "ERROR: $!\n";


## keep the file to a max of $ITEMS entries,
# insert an item into an RSS file and removes the oldest ones if
## there are already 5 items or more

my $rss = new XML::RSS;
$rss->parsefile("/Users/username/Sites/ripper.xml");
my $capture = "/Users/username/Sites/eclectic_$now.m4b";
my $popper = pop(@{$rss->{'items'}}) if (@{$rss->{'items'}} == 5);
if($popper){`rm $popper->{'guid'}`;}
my $date = `date "+%a, %d %h %Y %H:%M:%S %Z"`;
if ( -e $capture) { } else {die "$capture can't be found\n"};
$rss->add_item(
title => "Morning Becomes Eclectic - $date",
link => "http://legacy.kcrw.com/pl/NowPlayDayNew.html",
pubDate => $date,
guid => "$capture",
enclosure => { url=>"http://localhost/~username/eclectic_$now.m4b",
length => (stat($capture))[7],
type => 'audio/x-m4b'
},
mode => 'insert'
);
$rss->save("/Users/username/Sites/ripper.xml");

# cleanup after yourself
unlink "/tmp/eclectic_$now.m4a", "$fifo", "/tmp/output.xml" or die "couldn't delete: $!\n";


Tuesday, December 4, 2007

Make Firefox Use Leopard's Downloads Folder

Leopard introduced a new default location for files downloaded through Safari, the Downloads folder in the home folder. Making Firefox use this same download location is a bit tricky:

1. Delete the file com.apple.internetconfig.plist from Library/Preferences in your home folder.

2. In Firefox, open your preferences, choose the Main tab at the top and click "Choose..." to change the default download location to "/Users/yourusername/Downloads"









3. Restart Firefox.

Wednesday, November 21, 2007

Auto quitting your printer


One annoying thing about Leopard was that after you printed something the printer "application" stayed in the Dock until you closed it. In Tiger, the printer would auto quit after successfully printing your document. I realized you can get this behavior back in Leopard by simply right-clicking (or control-clicking) on the printer "application" on the Dock and checking "Auto Quit."

Thursday, October 25, 2007

Video Chatting with iChat and Netgear WGR614 Router


I struggled for a while trying to get video chatting to work with iChat. I tried disabling the OS X firewall and enabling port forwarding on the router, but nothing worked.

Finally I discovered the solution: disable the SPI Firewall on my router (a Netgear WGR614).

To do this, log into the router, choose "WAN Setup" from the left menu, check "Disable SPI Firewall," and click "Apply."

Wednesday, August 29, 2007

Easy Access to Windows from OS X


I have Windows XP installed on my Mac on another partition, using Boot Camp. One time saver I use is to have a shortcut to my Windows desktop on my OS X Finder:

It makes it really easy to move files back and forth between the two operating systems. Make sure when you format the partition in Boot Camp initially that you format it as FAT32 or else you won't be able to access the partition from OS X.

"Always Open With" From the Contextual Menu



One little shortcut I use to force a file to always open in a particular application is to right-click (or control-click) and then hold down the option key. The menu will change from "Open With" to "Always Open With" so that whatever application you choose will become the default application, but only for that file. It would be nice if you could change all the files of that type to open in that application but you can't, unless you "Get Info" and select "Change All."

Another interesting thing is that when you hold down the option key "Get Info" changes to "Show Inspector." It does the same thing, but perhaps there are file types that will have different behavior.

Wednesday, August 15, 2007

Making iSync Run Periodically


One annoying thing about iSync is that it can synchronize your contacts and calendar events between your Mac and your phone, but it does not do this automatically.

So I created a setup that automatically syncs my Razr with my Mac:

1. First open up the iSync application and click on your phone (this assumes you've already made your phone connect with your Mac. A menu will appear and click the appropriate boxes so that your phone synchronizes your contacts and calendars.




2. Create a text file named isync.plist inside your home folder:

/Users/joe/Library/LaunchAgents/

The isync.plist file should look like this:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>isync</string>
<key>OnDemand</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/Users/joe/.scripts/isync.pl</string>
</array>
<key>StartInterval</key>
<integer>3600</integer>
</dict>
</plist>

This will call our isync.pl perl script every hour (3600 seconds). You can change this to whatever you wish.

3. Open the Terminal and create a hidden directory in your home folder by entering this command:

mkdir ~/.scripts


Next move into this directory by typing:

cd ~/.scripts/


Create a perl file there titled isync.pl:

emacs isync.pl


The perl script should look like this:

#!/usr/bin/perl
use strict;
use warnings;

my $FLAGFILE = "/var/tmp/last-isync-date";
my $age = ((-M $FLAGFILE) || 0) * 24;
print $age;
exit if ($age && $age <>
system("osascript $ENV{HOME}/.scripts/isync.scpt; touch $FLAGFILE");


This script checks when the last time iSync updated your phone was. If it was more than 2 hours ago, then it attempts to run the update AppleScript. You can change the frequency by changing the number 2 to whatever you like in the second to last line.

4. Again in the .scripts directory, create an AppleScript file called isync.scpt:

cd ~/.scripts/
emacs isync.scpt

The AppleScript should look like this:

tell application "iSync"

if not syncing then
synchronize
repeat while syncing
delay 1
end repeat
quit
end if

end tell


That's all there is to it. Good luck and let me know if you have any problems getting this all to work.