#!/usr/bin/perl acquire('itunes.conf'); prepareitunesdb(); #$xmlfile = 'itunes.xml'; use XML::DOM; use DBI; my $file = $xmlfile; my $parser = XML::DOM::Parser->new(); my $doc = $parser->parsefile($file); $levelG = 0; foreach my $child1 ($doc->getChildNodes()){ $node1 = $child1; if ($node1->getNodeType == ELEMENT_NODE){ foreach my $node2 ($node1->getChildNodes()){ # TEXT_NODE = 3 # ELEMENT_NODE = 1 foreach my $node3 ($node2->getChildNodes()){ $node3Name = $node3->getNodeName; if ($node3Name =~ 'dict'){ #This is the where the song listing starts foreach my $node4 ($node3->getChildNodes()){ $node4Name = $node4->getNodeName; if ($node4Name =~ 'dict'){ foreach my $node5 ($node4->getChildNodes()){ $node5Name = $node5->getNodeName; foreach my $node6 ($node5->getChildNodes()){ $node6Name = $node6->getNodeName; $node6Data = $node6->getData; if ($node5Name =~ 'key'){ $dataField = $node6Data; } elsif($dataField =~ 'Track ID'){ $dataTrackID = $node6Data; } elsif($dataField =~ 'Name'){ $dataName = $node6Data; } elsif($dataField =~ 'Location'){ $dataLocation = $node6Data; } } } #Writing track data to the database insertTrack($dataTrackID,$dataName,'Artist Name',$dataLocation); } } } elsif($node3Name =~ 'array'){ #this is where the playlists start foreach my $node4 ($node3->getChildNodes()){ $node4Name = $node4->getNodeName; #everything in here should be 'dict' $dataPlaylistTracks = ''; foreach my $node5 ($node4->getChildNodes()){ #this should have us scrolling through the various playlists $node5Name = $node5->getNodeName; foreach my $node6 ($node5->getChildNodes()){ $node6Name = $node6->getNodeName; if ($node6->getNodeType() == TEXT_NODE){ $node6Data = $node6->getData; } if ($node5Name =~ 'array'){ #Here we will hae to take care of the playlist songlist foreach my $node7 ($node6->getChildNodes()){ $node7Name = $node7->getNodeName; foreach my $node8 ($node7->getChildNodes()){ if ($node7Name =~ 'key'){ $dataField = $node8->getData; } elsif($dataField =~ 'Track ID'){ $tempthing = $dataPlaylistTracks; $dataPlaylistTracks = "$tempthing,". $node8->getData; } } } } elsif($node5Name =~ 'key'){ $dataField = $node6->getData; } elsif($dataField =~ 'Name'){ $dataName = $node6->getData; } elsif($dataField =~ 'Playlist ID'){ $dataPlaylistID = $node6->getData; } } $prevNode5Name = $node5Name; $prevNode5Data = $node5Data; } #writing playlist data to the database if ($node4Name =~ 'dict'){ insertPlaylist($dataPlaylistID,$dataName,$dataPlaylistTracks); } } } } } } } copyFiles(); sub prepareitunesdb{ #This assumes that the itunes database has already been created, with two tables: #create statements: create table Track (ID int, Name varchar(100), Artist varchar(100), Location varchar(255), mythfilename text, mythintid int); #create statement: create table Playlist (ID int, Name varchar(100), PlaylistItems text); #alter statement: alter table Track add primary key (ID); #alter statement: alter table Playlist add primary key (ID); #Delete the contents of these tables $dbh=DBI->connect('dbi:mysql:',$mysqlusername,$mysqlpassword, {RaiseError=>1}) or die "Couldn't connect:".DBI->errstr(); $dbh->do("use $idbName"); $dbh->do("delete from Track"); $dbh->do("delete from Playlist"); } sub insertTrack{ my $trackID = $_[0]; my $trackName = $_[1]; my $trackArtist = $_[2]; my $trackLocation = $_[3]; #Ensure there arnt any ' in these strings $trackName =~ s/\'/\\\'/gi; $trackArtist =~ s/\'/\\\'/gi; $trackLocation =~ s/\'/\\\'/gi; $insert_string = "INSERT into Track (ID,Name,Artist,Location) values ($trackID,'$trackName','$trackArtist','$trackLocation')"; my $insert_handle = $dbh->prepare_cached($insert_string); $insert_handle->execute(); } sub insertPlaylist{ my $playlistID = $_[0]; my $playlistName = $_[1]; my $playlistItems = $_[2]; $insert_string = "INSERT into Playlist (ID,Name,PlaylistItems) values ($playlistID,'$playlistName','$playlistItems')"; my $insert_handle = $dbh->prepare_cached($insert_string); $insert_handle->execute(); } sub copyFiles{ $filesCopied = 0; $dospathlen = length $dospath; my $sth= $dbh->prepare("select * from Track") or die "Couldn't prepare statement: " . $dbh->errstr; $sth->execute() or die "Couldn't execute statement: " . $sth->errstr; while (@trackData = $sth->fetchrow_array()){ #Going through each of the Track records my $trackID = $trackData[0]; my $trackName = $trackData[1]; my $artistName = $trackData[2]; my $trackLocation = $trackData[3]; #Now to convert the dospath to the linux path we expect to find it in. #Lets make sure this file is in the right place if($trackLocation =~ m/^($dospath)/){ #The file is in the right location - now to determine the exact paths we will use $dosLocation = $trackLocation; $dosLocation =~ s/$dospath/$linuxpath/gi; #convert '%20' to '\ ' #itunes puts a lot of rubbish in its locations, so some work is necessary to #clean this out, and to convert the paths to stuff that will work in linux. #itunes uses '%20' for spaces - need to convert these to '\ ' $dosLocation =~ s/%20/\\ /gi; #convert '(' to '\(' $dosLocation =~ s/\(/\\\(/gi; #convert ')' to '\)' $dosLocation =~ s/\)/\\\)/gi; #convert '%5B' to '\[' and '%5D' to '\]' $dosLocation =~ s/%5B/\\[/gi; $dosLocation =~ s/%5D/\\]/gi; #convert ' to \' $dosLocation =~ s/\'/\\\'/gi; #convert & to \& $dosLocation =~ s/\&/\\&/gi; $linuxLocation = $trackLocation; $linuxLocationCheck = $linuxLocation; #now to clean up $linuxLocation in a similar fashion to $dosLocation - if any additional #checks are done for $dosLocation, they should be copied below for $linuxLocation $linuxLocation =~ s/$dospath/$mp3path/gi; $linuxLocation =~ s/%20/\\ /gi; $linuxLocation =~ s/\)/\\\)/gi; $linuxLocation =~ s/\(/\\\(/gi; $linuxLocation =~ s/%5B/\\[/gi; $linuxLocation =~ s/%5D/\\]/gi; $linuxLocation =~ s/\'/\\\'/gi; $linuxLocation =~ s/\&/\\&/gi; #not quite as much cleaning up is necessary for $linuxLocationCheck $linuxLocationCheck =~ s/$dospath/$mp3path/gi; $linuxLocationCheck =~ s/%20/ /gi; $linuxLocationCheck =~ s/\)/)/gi; $linuxLocationCheck =~ s/\(/(/gi; $linuxLocationCheck =~ s/%5B/[/gi; $linuxLocationCheck =~ s/%5D/]/gi; #in previous versions of itunes, there had been a / at the end of Location info. This is no more from version 6. #I'll leave this code here just in case though... #$linuxLocation = substr($linuxLocation,0,length($linuxLocation) - 1); #$linuxLocationCheck = substr($linuxLocationCheck,0,length($linuxLocationCheck) - 1); #$dosLocation = substr($dosLocation,0,length($dosLocation) - 1); #check if file exists on the linux file system if (-e $linuxLocationCheck){ #file exists - no need to do anything } else { #file does not exist - we need to copy it across $pathWithoutFilename = $trackLocation; $pathWithoutFilename =~ s/$dospath/$mp3path/gi; $pathWithoutFilename =~ s/%20/ /gi; #$pathWithoutFilename =~ =~ s/\)/\\\)/gi; $pathWithoutFilename =~ s/%5B/[/gi; $pathWithoutFilename =~ s/%5D/]/gi; $pathWithoutFilename = substr($pathWithoutFilename,0,length($pathWithoutFilename) - 1); while ($pathWithoutFilename =~ m/\//g){ $slashPos1 = pos($pathWithoutFilename); } my $pathWithoutFilename = substr($pathWithoutFilename,0,$slashPos1 - 1); #Create directory on linux system if it does not exist createDirIfNotExist($pathWithoutFilename); $dosLocation = $dosLocation; $linuxLocation = $linuxLocation; #copy($dosLocation, $linuxLocation) or die "File cannot be copied."; #for some reason copy just wouldnt work. print "copying from $dosLocation\n"; print "copying to $linuxLocation\n"; system("cp $dosLocation $linuxLocation"); $filesCopied = $filesCopied + 1; } } #now to update the mythfilename field #This should be updated with $linuxLocation, minus the contents of $mythmusicpath $mythfilename = $linuxLocation; $blankthing = ''; $mythfilename =~ s/$mythmusicpath//gi; #got it. Now to update it. $update_string = "UPDATE Track set mythfilename = \"$mythfilename\" where ID = $trackID"; my $update_handle = $dbh->prepare_cached($update_string); $update_handle->execute(); } print "Attempted to copy $filesCopied files.\n"; #"Attempted", as there is no guarantee it actually copied. weird characters in the file name #will trip it up. print "If new music has been added, you will now need to run the 'scan for new' function "; print "in MythTV.\n"; print "If new playlists have been added, you will have to run step2.pl.\n"; } sub createDirIfNotExist{ my $pathToCheck = $_[0]; if (-e $pathToCheck){ #do nothing } else{ #firstly find the location of the last "/" while ($pathToCheck =~ m/\//g){ $slashPos = pos($pathToCheck); } #Now $pos has the last / my $newPathToCheck = substr($pathToCheck,0,$slashPos - 1); createDirIfNotExist($newPathToCheck); mkdir($pathToCheck, 0777) || die "Cannot mkdir $pathToCheck: $!"; #777 is probably to much permission - will have to lock this down a little later. } } sub acquire { my($file) = @_; delete($INC{$file}); eval('require("$file")'); die "*** Failed to eval() file $file:\n$@\n" if ($@); }