#!/usr/bin/perl # djsync.pl -- Sync's tracks on your Dell DJ with MP3's on your filesystem. # I can be contacted at dan@daniel.net # # Version info: # # 0.1 -- Initial working version # 0.5 -- Bugs fixed, error handeling added use MP3::Info; # user defined variables $djtracklist = "/tmp/djtracks.txt"; $host_mp3_dir = "/stuff/mp3/dj/"; # program variables @host_files=""; $host_files_counter=0; @dj_tracks=""; $dj_tracks_counter=0; chdir($host_mp3_dir); get_host_tracks("", 1); get_dj_tracks(); parse_djtracks(); sync_to_dj(); sync_to_host(); cleanup(); sub get_host_tracks { # This loops through the $host_mp3_dir and builds an array of ALL files. my ($directory, $offset) = @_; opendir(DIR, $host_mp3_dir . $directory) or die ("Error opening: $!"); foreach (readdir(DIR)) { my $file = $directory . $_; # printFile(0, $file, $_, $offset); my $full_filename = $host_mp3_dir . $file; if ( ! -d $full_filename) { $host_files[$host_files_counter] = $full_filename; $host_files_counter++; } if ( -d $file && /[A-Za-z]/) { get_host_tracks($file . '/' , $offset + 1 ); next; } } } sub printFile { # Called from get_host_tracks() This function is deprecated and needs to be deleted. my ($type, $file, $name, $offset) = @_; my $full = $host_mp3_dir . $file; if ( ! -d $full) { $host_files[$host_files_counter] = $full; $host_files_counter++; } } sub get_dj_tracks { # This calls the program 'tracks' to get the track listings off the DJ and stores it # in file $djtracklist print "Getting DJ Tracks..."; system("tracks -E >$djtracklist"); print("\n"); } sub parse_djtracks { # This opens the file from get_dj_tracks and parses the file to get the filename in an # array. local $/="----------------------------------"; open(INPUT, $djtracklist) or die(print "Could not open $djtracklist: $!\n"); while() { ($dj_id) = /ID:\s*(\d*)/; ($dj_filename) = /FNAME:\s*(.*)/; $dj_tracks[$dj_tracks_counter] = $dj_filename; $dj_tracks_counter++; } close(INPUT) or die (print "Could not close: $!\n"); } sub sync_to_dj { # sync_to_dj() will get send all tracks on the host to the DJ if they dont exist on the dj # We do a embedded loop on the dj_tracks and host_files arrays. for ($h_counter = 0; $h_counter < @host_files; ++$h_counter) { $found = 0; for ($d_counter = 0; $d_counter < @dj_tracks && $found != 1; ++$d_counter) { $track_name = substr(@host_files[$h_counter],rindex(@host_files[$h_counter],'/')+1); # print "Comparing $track_name vs @dj_tracks[$d_counter] \n"; if ($track_name eq @dj_tracks[$d_counter]) { $found = 1; } } if (!$found) { # print "The track @host_files[$h_counter] exists on the Host, but not on the DJ.\n"; $track_info = new MP3::Info @host_files[$h_counter]; $track_time = int($track_info->{SECS}); if ($track_time eq 0) { # If the track time is 0, its not an MP3 file or one stupid song. # TODO: Put optional logging of skipped files. next; } # printf "@host_files[$h_counter] info:\nFilename: %s\nCodec: %s\nTitle: %s\nAlbum: %s\nArtist: %s\nGenre: %s\nTrack Num: %s\nYear: %s\nLength: %s\n", @host_files[$h_counter], "MP3", $track_info->{TITLE}, $track_info->{ALBUM}, $track_info->{ARTIST}, $track_info->{GENRE}, $track_info{TRACKNUM}, $track_info{YEAR}, $track_time; # make sure all the ID3 info is set, if not, make it null. sendtrack needs all input. $track_title = $track_info->{TITLE}; if (!$track_title) { $track_title=""; } $track_album = $track_info->{ALBUM}; if (!$track_album) { $track_album=""; } $track_artist = $track_info->{ARTIST}; if (!$track_artist) { $track_artist=""; } $track_genre = $track_info->{GENRE}; if (!$track_genre) { $track_genre=""; } $track_tracknum = $track_info->{TRACKNUM}; if (!$track_tracknum) { $track_tracknum=""; } $track_year = $track_info->{YEAR}; if (!$track_year) { $track_year=""; } print "Sending @host_files[$h_counter] to DJ\n"; system("sendtrack \"" . @host_files[$h_counter] . "\" MP3 \"" . $track_title . "\" \"" . $track_album . "\" \"" . $track_artist . "\" \"" . $track_genre . "\" \"" . $track_tracknum . "\" " . $track_year . "\"\" \"" . $track_time . "\""); } } } sub sync_to_host { # sync_to_host() will delete tracks off the DJ if they do not exist on the host for ($d_counter = 0; $d_counter < @dj_tracks; ++$d_counter) { $found = 0; for ($i = 0; $i < @host_files && $found != 1; ++$i) { $track_name = substr(@host_files[$i],rindex(@host_files[$i],'/')+1); # print "Comparing @dj_tracks[$d_counter] vs $track_name\n"; if ($track_name eq @dj_tracks[$d_counter]) { $found = 1; } } if (!$found) { if (@dj_tracks[$d_counter] eq "") { next; } # print "The File @dj_tracks[$d_counter] exists on the DJ, but not on the Host.\n"; # TODO: Put error handeling in getting $dj_id ($dj_id) = get_dj_trackid(@dj_tracks[$d_counter]); print "Deleting @dj_tracks[$d_counter] ($dj_id) off the DJ\n"; system("deltr $dj_id"); } } } sub get_dj_trackid { # This gets the trackid of the filename to send to the executable deltr. # TODO: The same filename can exist on the DJ multiple times. This code is broke here as it will # only find the first ID to try and delete. You will get an error to STDOUT. Note that running # djsync multiple times will eventually get rid of the MP3. Also note that djsync is inherently # flawed because it syncs based on unique filenames. It needs to be changed to sync via ID, but # this would involve storing this ID on the host as well (yuck). local $/="----------------------------------"; open(INPUT, $djtracklist) or die(print "Could not open $djtracklist: $!\n"); $dj_filename_searchstr = $_[0]; while() { ($dj_id) = /ID:\s*(\d*)/; ($dj_filename) = /FNAME:\s*(.*)/; if ($dj_filename eq $dj_filename_searchstr) { return ($dj_id); } } close(INPUT) or die (print "Could not close: $!\n"); } sub cleanup { # clean everything up to exit unlink($djtracklist) or die(print "Cannot delete tracklist file: $!\n"); }