############################################################################### # # itunes_backup_playlists.pl # # This script will export every non-Smart Playlist to a text file. Backups # will be a folder under the current directory, called "Playlist Backups" # # Copyright (C) 2007 Robert Jacobson # written by: Robert Jacobson (http://mysite.verizon.net/teridon/itunesscripts) # Last Updated: 28 Jan 2007 # Version 1.0 # # This script is GPL v2. see http://www.gnu.org/copyleft/gpl.html # ############################################################################### use File::Basename; my $PROGNAME = basename($0); my $VERSION = "1.0"; my $AUTHOR = "Robert Jacobson"; my $HOMEPAGE = "http://mysite.verizon.net/teridon/"; my $YEAR = 2007; my $GNU_URL = "http://www.gnu.org/copyleft/gpl.html"; { print "**************************************************************\n" . "$PROGNAME version $VERSION, Copyright (C) $YEAR $AUTHOR\n" . "Visit $HOMEPAGE for updates\n" . "$PROGNAME comes with ABSOLUTELY NO WARRANTY;\n". "This is free software, and you are welcome\n" . "to redistribute it under certain conditions\n" . "for details see $GNU_URL.\n" . "**************************************************************\n" . "\n" ; } use strict; use Win32::OLE; use Data::Dumper; use Encode; # Create a signal handler to destroy the iTunes object # in case our program quits before the end use sigtrap 'handler', \&quit, 'normal-signals'; ## Create the OLE Object my $iTunes = Win32::OLE->new('iTunes.Application') or die Win32::OLE->LastError(); my $dir = "Playlist Backups"; if (not -d $dir) { mkdir $dir or sub { print "Could not make directory $dir for backups\n"; quit(); } } # Get the possible sources my $sources = $iTunes->Sources(); my $sourcesCount = $sources->Count(); my $source = ''; my $sourceKind = ''; our $file; my $n = 1; $| = 1; # For each source, figure out kind for ($n = 1; $n <= $sourcesCount; $n++) { $source = $sources->Item($n); $sourceKind = $source->Kind(); # print "source no. " . $n . " is "; # print $sourceKind . " -- "; if ($sourceKind == 0) { print "Unknown Source\n"; } if ($sourceKind == 1) { print "Library Source\n"; # Get the playlists in the Library my $playlists = $source->Playlists(); my $num_playlists = $playlists->Count(); print "There are $num_playlists playlists\n"; # For each playlist, show the name and number of tracks for (my $j = 1 ; $j <= $num_playlists; $j++) { my $playlist = $playlists->Item($j); my $playlist_name = $playlist->Name(); print "\t$j : $playlist_name\n"; } print "Enter comma-separated playlist numbers: "; chomp (my $nums = ); my @nums; if ($nums =~ /all/i) { # Get all playlists that are not "Smart" @nums = (1 .. $num_playlists); #print @nums; quit; } else { @nums = split(/,/ , $nums); } for my $i (@nums) { print "Item $i\n"; my $playlist = $playlists->Item($i); my $playlist_name = $playlist->Name(); print "You selected $playlist_name\n"; # Make text file and headers $file = "${dir}\\${playlist_name}.txt"; my $answer = "n"; if (-f $file) { print "File $file exists. Overwrite [n]/y ? "; chomp ($answer = ); next unless ($answer =~ /^y/i); } open(OUT, ">$file") or die "Could not open output: $!"; # print byte order mark my $byte_order = "\xff\xfe"; #binmode(OUT, ":raw"); print OUT $byte_order; #close OUT; open(OUT, ">>:encoding(UTF-16LE)", $file) or die "Could not open output: $!"; my $string = "Name\tArtist\tComposer\tAlbum\tGrouping\tGenre\tSize\t" . "Time\tDisc Number\tDisc Count\tTrack Number\tTrack Count\t" . "Year\tDate Modified\tDate Added\tBit Rate\tSample Rate\t" . "Volume Adjustment\tKind\tEqualizer\tComments\tPlay Count\t" . "Last Played\tMy Rating\tLocation"; #utf8::upgrade($string); print OUT $string; newline(); my $tracks = $playlist->Tracks; my $num_tracks = $tracks->Count(); print "\t$num_tracks tracks\n"; my %seen; # Get all the tracks in the playlist for (my $k = 1 ; $k <= $tracks->Count ; $k++ ) { #print "num: " , $num_tracks , " Count: ", $tracks->Count , " k: ", $k , "\n"; my $track = $tracks->Item($k); my $track_kind = $track->Kind(); if ($track_kind == 1) { my ($name, $artist, $album, $grouping, $composer, $comments, $genre, $volume_adjustment, $category); my ($year, $track_number, $track_count, $disc_number, $disc_count, $bpm, $compilation, $rating, $equalizer, $description); my ($size, $time, $date_mod, $date_added, $play_count, $last_played, $location, $kind, $sample_rate, $bitrate); $name = $track->name(); print OUT "$name\t"; $artist = $track->artist(); print OUT "$artist\t"; $composer = $track->composer(); print OUT "$composer\t"; $album = $track->album(); print OUT "$album\t"; $grouping = $track->grouping(); print OUT "$grouping\t"; $genre = $track->genre(); print OUT "$genre\t"; $size = $track->size(); print OUT "$size\t"; $time = $track->duration(); print OUT "$time\t"; $disc_number = $track->discnumber(); printf OUT "%s\t", $disc_number ? $disc_number : ""; $disc_count = $track->disccount(); printf OUT "%s\t", $disc_count ? $disc_count : ""; $track_number = $track->tracknumber(); printf OUT "%s\t", $track_number ? $track_number : ""; $track_count = $track->trackcount(); printf OUT "%s\t", $track_count ? $track_count : ""; $year = $track->year(); printf OUT "%s\t", $year ? $year : ""; $date_mod = $track->ModificationDate(); my $date_mod_date = $date_mod->Date("M/d/yyyy "); my $date_mod_time = $date_mod->Time("h:mm tt"); if ($date_mod_date eq '12/30/1899 ') { print OUT "\t"; } else { print OUT $date_mod_date,$date_mod_time,"\t"; } $date_added = $track->DateAdded(); my $date_added_date = $date_added->Date("M/d/yyyy "); my $date_added_time = $date_added->Time("h:mm tt"); if ($date_added_date eq '12/30/1899 ') { print OUT "\t"; } else { print OUT $date_added_date,$date_added_time,"\t"; } $bitrate = $track->bitrate(); print OUT "$bitrate\t"; $sample_rate = $track->SampleRate(); print OUT "$sample_rate\t"; $volume_adjustment = $track->volumeadjustment(); printf OUT "%s\t", $volume_adjustment ? $volume_adjustment : ""; $kind = $track->kindasstring(); print OUT "$kind\t"; $equalizer = $track->eq(); print OUT "$equalizer\t"; $comments = $track->comment(); print OUT "$comments\t"; $play_count = $track->playedcount(); printf OUT "%s\t", $play_count ? $play_count : ""; $last_played = $track->playeddate(); my $last_played_date = $last_played->Date("M/d/yyyy "); my $last_played_time = $last_played->Time("h:mm tt"); if ($last_played_date eq '12/30/1899 ') { print OUT "\t"; } else { print OUT $last_played_date,$last_played_time,"\t"; } $rating = $track->rating(); printf OUT "%s\t", $rating ? $rating : ""; $location = $track->location(); print OUT "$location"; newline(); } else { print "ERROR - unexpected track kind $track_kind\n";#, Dumper $track; } } close (OUT); } } } # Destroy the object. Otherwise zombie object will come back # to haunt you quit(); sub quit { # This destroys the object undef $iTunes; exit; } sub newline { # This was easier to type than encoding all my strings with $foo = encode($string), so there! close OUT; open (OUT, ">>$file"); binmode OUT; # put OUT in raw binary mode print OUT "\x0d\x00\x0a\x00"; # This is the "newline" that iTunes expects # Go back to UTF16-LE encoding open (OUT, ">>:encoding(UTF-16LE)", $file); }