#!/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");
}