if its too loud, turn it down

Monday, June 22, 2009

Record streamed albums to MP3 using WireTap

There are some sites popping up that let you stream entire albums (i.e. not just samples like Amazon). For example, deezer.com and lala.com (on lala.com, first play only is free). That's great, but not very portable. I listen to alot of music on my iPod. So here's a way to use Ambrosia Software's excellent WireTap Studio, to record the stream and save entire albums as separate mp3s which can be listened to on an iPod.

WireTap allows you to record any audio signals on your mac. You can set it to record all audio passing through the sound device, or only audio that's playing in a particular application (say, a streaming radio station playing in Safari). A really nice feature of WireTap is that you can mute the other audio sources while it's recording. So for example, I can using WireTap to record an audio stream in Firefox while listening to a playlist in iTunes. The two audio signals will not interfere with one another. So what I'm doing here is streaming an entire album from one of the sites listed above (in their flash browser music player), and having WireTap record the audio stream from the browser, and split out the individual tracks.

Once that's done, the script I wrote (included below) uses a directory of MP3s (from WireTap) as input, and prompts you for band/album name. With that info it queries the MusicBrainz database to look up album and track data for MP3 tagging purposes. It then adds the new tracks to your iTunes library so they don't have to be manually added. From there they can be easily added to an iPod.

The sound isn't great-quality (96kbps I believe) but its a good way to listen to music to see if you like it or not. Then, of course, you buy it. Just a reminder: never distribute copyrighted music.

Step 1: Set up a new WireTap recording session. Open WireTap and Select "Window" menu -> Recording Sessions. When the "Recording Sessions" dialog is open, press the "+ New" button, then the "Saving" tab. Enter these settings:

Description: Enter "Browser Record"
Select "Name Automatically"
Save Files To: Library
Select "Prefix" and enter "0"
Suffix: Increment
Split: On Silence (Configure: -64.0db Minimum Silence Duration: 0.7s)
Un-check "Record Lossless Original"
Un-check "Open Recording In Editor"

WireTap Recording Sessions Saving Tab
NOTE ON "SPLIT" CONFIGURATION: The duration of silence is what tells WireTap that a song has ended and another begins. Without this, you'd end up with one long track as your album. I've found 0.7s to be a good duration, but you may need to configure.

Step 2: Configure sound source. Click the "source" tab and use these settings:

Source One: select Safari (or Firefox)
Source Two: none
Record: Trim All Silence (leave configuration as-is
Mute Mac Audio Sources: checked

WireTap Recording Sessions Source Tab
Step 3: Configure format. Select "Format" tab. I use 192kbps so that little or no quality is lost in the encoding of the stream. You're probably OK with 128kbps is you want a smaller filesize though. Save your new recording session.

WireTap Recording Sessions Format Tab
Step 4: Start the recording. In the WireTap "recording session" window, select the "Browser Record" session you jsut created and click the "start" button. It will start "listening" to your configured source (browser), but it won't actually record until sound starts streaming. A small "on air" logo will appear on the left side of your session.

Find your desired album on one of the sites mentioned above. If it's lala.com just click the "Queue" button on the album's page and it adds all tracks to your queue (you only get one free play on lala, so don't screw up!). Then press the play button on the queue at the top of the page. On Deezer, just press play on the first track. This will begin the actual recording and you will see a duration timer in your recording session. It starts anew with each new track.

Browser Screen
Step 5: Export recordings from WireTap. Once your recording is done, click the "Stop" button in the "recording sessions" window. Select Window -> Library and you will see your tracks in there. The last track will probably have a length of 00.00 and can safely be deleted. Highlight all tracks and click "Local" (at bottom) to export as mp3s. In the file dialog that pops up navigate to your Desktop and click "New Folder" and name it "output".

WireTap Library
Step 6: Run script to name and tag tracks. So now we have a set of MP3s which is great, but they need to be a) re-named so the filenames reflect what they are b) tagged with ID3 info so they show properly in the iTunes library c) physically moved into your music library. At this point you could manually re-name the files, drag them into iTunes and tag them manually by right-clicking each one and going Get Info -> "Info" tab. That's the thing to do if you're not script-inclined. But if you are, the script below automates the job.

The script below can be saved somewhere in your user directory (I have a ~/bin folder for scripts like this) as "cddb.pl", even though it really has nothing to do with the actual CDDB. After chmod-ing it to 755 (also adjust the $libdir variable to the location of your music library), you can call it with the first argument being the location of the folder we just created. For example:
~/bin/cddb.pl ~/Desktop/output/
You will then be prompted with the info it needs to name and tag the MP3s. The screenshot below illustrates a sample session. Click to enlarge.

MusicBrainz Script Output
Click "expand source" to view script's code.
#!/usr/bin/perl

# HOW TO SET UP A WIRETAP BROWSER RECORD
#
# Open the Wiretap Recording Sessions window.  Click "New" button.  Add the following info to
# the "Saving" tab:
#
# Description: Enter "Browser Record"
# Select "Name Automatically"
# Save Files To: Library
# Select "Prefix" and enter "0"
# Suffix: Increment
# Split: On Silence (Configure: -64.0db Minimum Silence Duration: 0.7s)
# Un-check "Record Lossless Original"
# Un-check "Open Recording In Editor"
#
# In the "Source" tab:
#
# Source One: Safari (or Firefox)
# Source Two: None
# Record: Trim All Silence (Configure: -64.0db Minimum Silence Duration: 2.0s)
# Check "Mute Mac Audio Sources"
#
# In the "Format" tab:
#
# Presets: MP3-High Quality
#
# Leave the "Effects", "Processing" and "Schedule" tabs at their defaults and click OK.
#
# To record, FIRST click on the "Browser Record" Line in Recording Sessions and then "Start"
# THEN press "play" on whatever you are playing in the browser.  You will not hear sound,
# because it's muted.  Let the recording play in its entirety, and press "Stop" in
# Recording Sessions when it's done.  If everything went well, one track per each song
# will appear in the Library and should be ready for export.
#
# Note: Often the last track is empty - look at the times of the track and delete it if it's there.
#
# HOW TO SPLIT TRACKS IN WIRETAP SO THAT THEY WILL BE NAMED PROPERLY HERE
#
# When a recorded track in wiretap actually contains two tracks it needs to be manually split.
# Double-click on the track in the Library to load it in the editor.  Find where the track is 
# to be split (by track length or just by looking) and click there to set the cursor at that point.
# Then in the "Editor" menu choose "add marker".  Then in the Editor menu select "Split Audio"
# In the dialog that appears, in the Name field add the original name of the track.  Select
# Save to Library, and Split On "Marker".  Click OK and it will create two new tracks in the Library:
#
# [track name]_split
# [track name]_New Marker [numbered if more than one]
# ...
#
# The one with the "_split" suffix is the first track, and the "_New Marker" is the second (and so forth).
# Re-name them as such:
#
# [track name]a
# [track name]b
# ...
#
# Then delete the original track.
#
# OTHER NOTES
#
# - To use the non-default (wiretap) source folder specify it when calling this script:
#   $ cddb.pl /Users/guest/Desktop/new_folder/
#   This is useful when you want to tag and add a set of mp3s recorded from somewhere else.
# One caveat is they *have* to appear in alphabetical order when you type ls -al
#

use strict;
use WebService::MusicBrainz::Release;
use WebService::MusicBrainz::Artist;
use WebService::MusicBrainz::Track;
use MP3::Tag;
use File::Copy;

# location of raw mp3 files
my $datadir = '/Users/user/Music/Import/wiretap/';
my $libdir = '/Volumes/numchux/mp3/';

# itunes stuff
my $add_to_itunes = "Yes"; # works only on Mac OS X - set to No for all other OS's
my $itunes_bookmarkable = "No";

# check if we're supposed to use an alternate data dir
my $altdir = 0;
if ( ($ARGV[0]) && (-d $ARGV[0]) ) {
 $altdir = 1;
 $datadir = $ARGV[0];
}

# put the data files in an array sorted by date/time created - accessible by $fullpaths[]
my @filelist = ();
my @fullpaths = ();
my @todelete = ();

# only do the following for the wiretap records:
if (!$altdir) {

 # rename the files so we can sort by name
 opendir(DIR, $datadir) || die "can't opendir $datadir: $!";
 my @prefiles = readdir(DIR);
 closedir(DIR);
 my $mp3count = 0;
 foreach my $prefile (@prefiles) {
  my $curfile = $datadir . $prefile;
  if ($prefile =~ /\.[Mm][PpOo][3Vv]$/) {
   $mp3count++;
   my $skip = 0;
   my $final_file;
   my $quoted = quotemeta($curfile);
   my $basename = `/usr/bin/basename $quoted`;
   $basename = &stripCrap($basename);
  
   if ($basename =~ /^0\.original\.([Mm][PpOo][3Vv])$/) {
    $final_file = $datadir . '00' . '.original.' . $1;
   } elsif ($basename =~ /^0 (\d\d\d?)\.original\.([Mm][PpOo][3Vv])$/) {
    $final_file = $datadir . $1 . '.original.' . $2;
   } elsif ($basename =~ /^0 (\d\d\d?[a-zA-Z])\.original\.([Mm][PpOo][3Vv])$/) {
    $final_file = $datadir . $1 . '.original.' . $2;
   } elsif ($basename =~ /^0 (\d)\.original\.([Mm][PpOo][3Vv])$/) {
    $final_file = $datadir . '0' . $1 . '.original.' . $2;
   } elsif ($basename =~ /^0 (\d[a-zA-z])\.original\.([Mm][PpOo][3Vv])$/) {
    $final_file = $datadir . '0' . $1 . '.original.' . $2;
   } else {
    $skip = 1;
   }
   if (!$skip) {
    # move file to its new, properly aplh'd name
    move($curfile,$final_file);
   }
   
   # if it's a .mov file we need to convert it
   if ($final_file =~ /^(.*?)\.([Mm][Oo][Vv])$/) {
    my $newfile = $1 . '.mp3';
    my $output = `/sw/bin/ffmpeg -i $final_file -ar 44100 -ab 160k $newfile`;
    if (-e $newfile) {
     unlink($final_file);
     $final_file = $newfile;
     $curfile = $newfile;
    }
   } # end check for .mov
   
   # add files to array so we delete after we;'re done
   push(@todelete,$curfile);
  }
  if ($prefile =~ /\.meta\.plist$/) {
   push(@todelete,$curfile);
  }
 }
 
 # if we don't have an mp3count, die
 if ($mp3count==0) {
  print "no mp3s to convert\n"; exit;
 }

} # end if for !$altdir (is a wiretap record)

# sort data dir by name
opendir(DH, $datadir) || die "Can't open directory $datadir: $!\n"; 
 @filelist = sort { "$datadir/$b" <=> "$datadir/$a" } grep { -f "$datadir/$_" && /\.[Mm][PpOo][3Vv]$/ } readdir DH;
closedir(DH);

my $i=1;
my $tracks = @filelist;
foreach my $file (@filelist) {
 $fullpaths[$i] = $datadir . $file;
 #print "$fullpaths[$i]\n";
 $i++;
}

# prompt user for artist name
my $artist_name  = &promptUser("Enter Artist Name ","");
if ( !$artist_name ) {
 print "No artist name entered, quitting\n";
 exit;
}

my $at = WebService::MusicBrainz::Artist->new();
my $response = $at->search({ NAME => $artist_name, LIMIT => 15 });
my @artists = $response->artist_list(); # get first in list

# get the most relevant search results for query
my @artist_id_arr = ();
my @artist_name_arr = ();
my $i = 1;
my ($artist_id,$artist_name);
foreach my $artist (@artists) {
 $artist_id_arr[$i] = $artist->{id};
 my $tmpname = $artist->{name};
 $tmpname =~ s/[^[:ascii:]]+//g;
 $artist_name_arr[$i] = $tmpname;
 print "[${i}] $tmpname\n";
 $i++;
}
my $artist_number  = &promptUser("Matching Artist ","1");
if ($artist_id_arr[$artist_number]) {
 $artist_id = $artist_id_arr[$artist_number];
 $artist_name = $artist_name_arr[$artist_number];
} else {
 print "Invalid artist number entered, quitting\n";
 exit;
}

# get the releases for specified artist
my $rl = WebService::MusicBrainz::Release->new();
my $response = $rl->search({ ARTISTID => "$artist_id" });
my @releases = $response->release_list();

my @release_id_arr = ();
my @release_name_arr = ();
my @release_date_arr = ();
my $i = 1;
my ($release_id, $release_name, $release_date);
foreach my $release (@releases) {
 $release_id_arr[$i] = $release->{id};
 $release_name_arr[$i] = $release->{title};
 my $date = "unknown date";
 if ($release->{release_event_list}->{events}[0]->{date}) {
  $release->{release_event_list}->{events}[0]->{date} =~ /^([0-9]{4})/;
  $date = $1;
 }
 $release_date_arr[$i] = $date;
 print "[${i}] $release->{title} ($date, $release->{track_list}->{count} tracks)\n";
 $i++;
}
my $release_number  = &promptUser("Album Name ","1");
if ($release_id_arr[$release_number]) {
 $release_id = $release_id_arr[$release_number];
 $release_name = $release_name_arr[$release_number];
 $release_date = $release_date_arr[$release_number];
} else {
 print "Invalid release number entered, quitting\n";
 exit;
}

# List the tracks
my $release_search = $rl->search({ MBID => "$release_id", INC => 'tracks' });
my $release_search_first = $release_search->release();
my $track_ws = WebService::MusicBrainz::Track->new();
my $track_num = 0;

my @final_tracks = ();
foreach my $track (@{ $release_search_first->track_list()->tracks() }) {
 $track_num++;

 # query track data with artist details
 # artist at the release level could be "Various Artists",
 #   so we need to query each track for it's artist
 my $track_response = $track_ws->search({ MBID => $track->id(), INC => 'artist' });

 my $found_track = $track_response->track();
 print $track_num, ": ", $found_track->title(), " - ", $artist_name,  " - ", $release_name,  " - ", $release_date, "\n";
 
 # write this info to the file
 &id3v2tag($fullpaths[$track_num],$found_track->title(),$release_date,$artist_name,$release_name,"rock","lame");
 
 # rename the mp3 file
 my $curtrack = $track_num;
 if ($curtrack < 10) { $curtrack = '0' . $curtrack; }
 my $curtrackname = replaceSpace(stripNonAlph($found_track->title()));
 my $trackfinal = $datadir . $curtrack . '_' . $curtrackname . '.mp3';
 move($fullpaths[$track_num],$trackfinal) or die "Move failed: $!";
 push(@final_tracks,$trackfinal);
}

# if our libdir is attached, let's move the stuff there.
if (not(-d $libdir)) { print "library not attached, not moving files.  But they are done.\n"; exit; }

my ($artistlib,$albumlib,$tmp1artist,$tmp2artist,$tmp3artist,$tmp1album,$tmp2album,$tmp3album);
# check if the artist dir exists
$tmp1artist = $libdir . $artist_name . '/';
$tmp2artist = $libdir . replaceSpace(stripNonAlph(lc($artist_name))) . '/';
$tmp3artist = $libdir . capWords($artist_name) . '/';

if (-d $tmp1artist) { 
 $artistlib = $tmp1artist; 
} elsif (-d $tmp2artist) {
 $artistlib = $tmp2artist; 
} elsif (-d $tmp3artist) {
 $artistlib = $tmp3artist; 
} else {
 system("mkdir $tmp2artist");
 $artistlib = $tmp2artist;
}
print "ARTIST: $artistlib\n";

# check if the album dir exists
$tmp1album = $artistlib . $artist_name . '/';
$tmp2album = $artistlib . replaceSpace(stripNonAlph(lc($release_name))) . '/';
$tmp3album = $artistlib . capWords($release_name) . '/';

if (-d $tmp1album) { 
 $albumlib = $tmp1album; 
} elsif (-d $tmp2album) {
 $albumlib = $tmp2album; 
} elsif (-d $tmp3album) {
 $albumlib = $tmp3album; 
} else {
 system("mkdir $tmp2album");
 $albumlib = $tmp2album;
}

# move the tracks to the library
print "MOVING TRACKS TO: $albumlib\n";
foreach my $fulltrack (@final_tracks) {
 move($fulltrack,$albumlib) or die "Move failed: $!";
}

# clean up files
foreach my $delete (@todelete) {
 unlink($delete);
}

# add to itunes library
if ($add_to_itunes eq 'Yes') {
 
 # prompt user for what playlist to add (if any)
 my $add_to_itunes_playlists  = &promptUser("Enter playlist you want to add these to [blank for none] ","");
 
 # add all new tracks to an array
 my @additions = ();
 opendir(DH, $albumlib) || die "Can't open directory $albumlib: $!\n"; 
  my @newtrax = sort { "$albumlib/$b" <=> "$albumlib/$a" } grep { -f "$albumlib/$_" && /\.[Mm][Pp][3]$/ } readdir DH;
 closedir(DH);
 
 # loop thru array and add tracks to itunes
 foreach my $newtrack (@newtrax) {
  my $fullnewtrack = $albumlib . $newtrack;
  my $return = &iTunes($fullnewtrack,$add_to_itunes_playlists,$add_to_itunes,$itunes_bookmarkable);
  if ($return) {
   print "track $fullnewtrack added to itunes\n";
  }
 }
} # end if for add to itunes

print "Done\n";
exit;

################### SUBS ###################


# for getting the basename of a file without using a module
sub basename {
 my $file = shift;
 $file =~ s!^(?:.*/)?(.+?)(?:\.[^.]*)?$!$1!;
 return $file;
} # end sub basename

sub stripNonAlph {

 my($text) = shift;
 $text =~ s/([^0-9a-zA-z ])//g;
 return ($text);

} # end sub strip non alph

sub replaceSpace {
 my ($text) = shift;
 $text =~ s/ /_/g;
 return $text;
}

sub capWords {
 my ($text) = shift;
 $text =~ s/\b(\w)/\u$1/g;
 return $text;
}

sub trim {

 my $text = shift;
 $text =~ s/^\s+//;
 $text =~ s/\s+$//;
 return $text;
}

sub stripCrap {

 my $string = shift;
 $string =~ s/\n//g;
 $string =~ s/\r//g;
 $string =~ s/\r\n//g;
 $string =~ s/\012//g;
 $string =~ s/\015//g;
 $string =~ s/\012\015//g;

 return($string);
}

sub id3v2tag {
 # adds id3v2 tag to mp3s

 my ($file,$title,$year,$author,$album,$genre,$encoder) = @_;
 my $mp3 = MP3::Tag->new($file);
 $mp3->get_tags();
 $mp3->new_tag("ID3v2");
 $mp3->{ID3v2}->add_frame("TALB", "$album");
 $mp3->{ID3v2}->add_frame("TIT2", "$title");
 $mp3->{ID3v2}->add_frame("TPE1", "$author");
 $mp3->{ID3v2}->add_frame("TCON", "$genre");
 $mp3->{ID3v2}->add_frame("TSSE", "$encoder");
 $mp3->{ID3v2}->add_frame("TYER", "$year");
 $mp3->{ID3v2}->write_tag;
 $mp3->close();

} # end sub id3v2tag

sub promptUser {

   #-------------------------------------------------------------------#
   #  two possible input arguments - $promptString, and $defaultValue  #
   #  make the input arguments local variables.                        #
   #-------------------------------------------------------------------#

   my ($promptString,$defaultValue) = @_;

   #-------------------------------------------------------------------#
   #  if there is a default value, use the first print statement; if   #
   #  no default is provided, print the second string.                 #
   #-------------------------------------------------------------------#

   if ($defaultValue) {
      print $promptString, "[", $defaultValue, "]: ";
   } else {
      print $promptString, ": ";
   }

   $| = 1;               # force a flush after our print
   $_ = ;         # get the input from STDIN (presumably the keyboard)


   #------------------------------------------------------------------#
   # remove the newline character from the end of the input the user  #
   # gave us.                                                         #
   #------------------------------------------------------------------#

   chomp;

   #-----------------------------------------------------------------#
   #  if we had a $default value, and the user gave us input, then   #
   #  return the input; if we had a default, and they gave us no     #
   #  no input, return the $defaultValue.                            #
   #                                                                 #
   #  if we did not have a default value, then just return whatever  #
   #  the user gave us.  if they just hit the  key,           #
   #  the calling routine will have to deal with that.               #
   #-----------------------------------------------------------------#

   if ("$defaultValue") {
      return $_ ? $_ : $defaultValue;    # return $_ if it has a value
   } else {
      return $_;
   }
} # end sub promptuser

#################################################################################################
###################                ITUNES-SPECIFIC SUBROUTINES           #####################
#################################################################################################

sub iTunes {
 # handles vairous itunes tasks that will only work on a mac os x
  
 my ($file,$add_to_itunes_playlists,$add_to_itunes,$itunes_bookmarkable) = @_;

 # check that we're on Darwin and only do this stuff if we are
 my $darwin = checkForDarwin();
 if ( ($darwin) && ($add_to_itunes eq 'Yes') ) {
 
  # if the files exists, add to itunes library
  my $finder;
  if (-e $file) {
   $finder = addToiTunes($file);
  }
  
  # set the track to bookmarkable
  if (($finder) && ($itunes_bookmarkable eq 'Yes')) {
   my $result = setBookMarkable($finder);
  }
  
  # add it to a itunes playlist(s)
  if ( ($add_to_itunes_playlists) && ($finder) ) {
   
   # split the string into an array on commas (can contain multiple playlists)
   my @playlists = split(/,/,$add_to_itunes_playlists);
   
   # loop thru the playlists...
   foreach my $itunes_playlist (@playlists) {
   
    $itunes_playlist = trim(stripNonAlph($itunes_playlist));
    # check if the pl exists
    my $pl_check = checkPlaylistExists($itunes_playlist);
    if ( (not($pl_check =~/^\d/)) || (not($pl_check >= 1 )) ) {
     # create the playlist
     $pl_check = createPlaylist($itunes_playlist);
    } # end if for playlist does not exist
    
    if (($pl_check =~/^\d/) && ($pl_check >=1 )) {
     # check to make sure playlist(s) exist
     my $return = addToPlaylist($finder,$itunes_playlist);
    } # end if for playlist exists
   
   } # end loop thru itunes playlists
  } # end if for add to playlists
 
 } # end if for is a mac and wants stuff added to lib
 
 return 1;

} # end sub iTunes

sub checkForDarwin {
 # checks that we're running darwin
 
 my $darwin = `uname -s`;
 $darwin = trim(stripNonAlph(lc($darwin)));
 if ($darwin =~ /^darwin/) {
  return 1;
 } else {
  return 0;
 }

} # end sub for check for darwin

sub addToiTunes {
 # adds the file to the itunes library
 
 my $file = shift;
 my $ref = `/usr/bin/osascript -e 'tell application "iTunes" to add POSIX file "$file"'`;
 $ref = &stripNonAlph($ref);
 sleep 2; # sleep so we can allow itunes to process is
 return ($ref);
 
} # end sub addToiTunes

sub setBookMarkable {
 # sets the track so it remembers its last playback position (set the bookmarkable flag to true)
 
 my $finder = shift;
 my $ref = `/usr/bin/osascript -e 'tell application "iTunes" to set bookmarkable of $finder to true'`;
 $ref = &stripNonAlph($ref);
 return ($ref);
 
} # end setBookMarkable

sub addToPlaylist {
 # adds the file to a particular playlist
 
 my ($finder,$playlist) = @_;
 my $ref = `/usr/bin/osascript -e 'tell application "iTunes" to add (get location of $finder) to playlist "$playlist"'`;
 $ref = &stripNonAlph($ref);
 return ($ref);

} # end sub addtoplaylist

sub checkPlaylistExists {
 # checks if the itunes playlist exists
 
 my $playlist = shift;
 $playlist = &stripNonAlph($playlist);
 my $exists=`/usr/bin/osascript <<END
 tell application "iTunes"
  set myCount to 0
  repeat with i from 1 to (the count of the playlists)
   set this_playlist to playlist i
   try
    if the name of this_playlist is "$playlist" then
     set myCount to myCount + 1
    end if
   end try
  end repeat
  return myCount
 end tell
 END`;
 
 $exists = &stripNonAlph($exists);
 return ($exists);
} # end check if playlist exist

sub createPlaylist {
 # creates an itunes playlist
 
 my $playlist = shift;
 $playlist = &stripNonAlph($playlist);
 my $newpl=`/usr/bin/osascript <<END
 tell application "iTunes"
  set myList to make new playlist
  set name of myList to "$playlist"
  return 1
 end tell
 END`;
 $newpl = &stripNonAlph($newpl);
 return ($newpl);
 
} # end sub createplaylist

sub checkForiTunes {
 # check to see if itunes is installed
 # going to work only on a mac of cours
 
 my $installed=`/usr/bin/osascript <<END
 tell application "Finder"
  try
   exists application file id "hook"
   return 1
  on error
   return 0
  end try
 end tell
 END`;
 $installed = &stripNonAlph($installed);
 return ($installed);

} # end sub check for itunes install

When the script is done running, the "output" folder on your desktop can be safely deleted, and the new tracks will be accessible in iTunes.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.