#!/usr/bin/perl #H# This script performs regular maintenance tasks to keep my database in sync with #H# my file system. #H# #H# Commands: #H# info [filename] #H# Prints the information about a file from sored in the db #H# add [filename] #H# Initially adds a file to the system and the db. #H# File will be moved to /home/asylum/kmk/media/Music/tracker/ #H# rename [old filename] [new filename] #H# Renames a file and updates the db. #H# rm [filename] #H# Removes a file from both the database and the filesystem! #H# verify [filename] #H# Verifies the validity of a file based on the md5sum sored in the db #H# verifyall [q] #H# Verifies all files in the db #H# [q] is an optional parameter that silences all of the "OK" lines. #H# md5 [filename] #H# Updates the md5sum in the db # print out help info if requested if ($ARGV[0] eq "-h" || $ARGV[0] eq "--help" || $ARGV[0] eq "help" || $ARGV[0] eq "") { open (SELF, $0); while () { if ($_ =~ /^#H# /) { $_ =~ s/^#H# //; print $_; } } exit; } # open the music database and load modules use Date::Format; use DBI; $DB= DBI->connect("DBI:mysql:music:asylum.sanitarium.net" . ";mysql_read_default_file=/home/asylum/kmk/.my.cnf", kmk, $password); # figure out which command we are running here $Command=$ARGV[0]; chomp $Command; if ($Command ne "verifyall") { # Might as well figure all this crap out before even bothering to figure out what # command we are processing since almost all will need it. # The verifydir and index commands don't use any params so there is nothing to # do for them until the command specific stuff. # The file name is almost always the first param (after the command) so suck it in now # and replace it later if needed. $FileNameParam=$ARGV[1]; # find the real full path to the file name so I can use relative paths on the CLI $FullPath=`realpath "$FileNameParam"`; chomp $FullPath; @PathParts = split (/\//,$FullPath); foreach $PathPart (@PathParts) { $FileName=$PathPart; } if ($Command ne "add") { # Might as well grab this here to unless the command isn't going to need it. # This pulls the current info on the file out of the db so it will be on hand later. # The add and tag commands assume the file isn't in the db yet. $ID="N"; $SafeFileName=$FileName; $SafeFileName =~ s/'/\\'/g; $QueryString="select * from trackerz where FileName='$SafeFileName'"; $QueryHandle=$DB->prepare($QueryString); $QueryHandle->execute; while (@Data=$QueryHandle->fetchrow_array) { ($ID,$FileName,$FileSize,$Format,$Title,$Length,$Tracks,$Samples,$Patterns,$DateAdded,$Artist,$md5sum)=@Data; } } } if ($Command eq "info") { # code for info command # sanity check to make sure the file actually existed in the query above. if ($ID eq "N") { die "File not found in database!\n"; } print "ID: $ID\n"; print "FileName: $FileName\n"; print "FileSize: $FileSize\n"; print "Format: $Format\n"; print "Title: $Title\n"; print "Length: $Length\n"; print "Tracks: $Tracks\n"; print "Samples: $Samples\n"; print "Patterns: $Patterns\n"; print "DateAdded: $DateAdded\n"; print "Artist: $Artist\n"; print "md5sum: $md5sum\n"; } elsif ($Command eq "add") { # code for add command. # quick check for params before we start touching things. # make sure that the file exists. Then get info about it. open (FH, "$FileNameParam") || die "Can't open file."; ($FileSize,$Ctime)=(stat(FH))[7,10]; close(FH); #$DateAdded=`date +%Y-%m-%d`; #chomp $DateAdded; # grab an md5sum... open (TH, qq[md5sum "$FileNameParam" |]); $MD5SumText=; close (TH); chomp $MD5SumText; ($MD5Sum,$junk)=split (/ /,$MD5SumText,2); # check for already existing file or md5sum (both are fatal) $QueryString="select FileName,md5sum from trackerz where FileName='$SafeFileName' or md5sum='$MD5Sum'"; $QueryHandle=$DB->prepare($QueryString); $QueryHandle->execute; while (@Data=$QueryHandle->fetchrow_array) { ($ExistingFileName,$ExistingMD5Sum)=@Data; if ($ExistingFileName eq $FileName) { die "ERROR: $ExistingFileName already exists!\n"; } if ($ExistingMD5Sum eq $MD5Sum) { die "ERROR: $ExistingFileName is the same file!\n"; } } # grab the details that file can grab $FileTxt=`file -b "$FileNameParam"`; chomp $FileTxt; ($FileTypeText,$Junk)=split (/:/,$FileTxt,2); ($FileType,$Junk)=split (/ - /,$FileTypeText,2); $FileType =~ s/data//; $FileType =~ s/Title//; $FileType =~ s/module//i; $FileType =~ s/sound//; $FileType =~ s/ +/ /g; $FileType =~ s/ $//; $FileType =~ s/^.-channel //; $FileType =~ s/^$/unknown/; # Grab the data that xmp can provide. $Length="00:00:00"; $Patterns=0; $Samples=0; $Tracks=0; open (XMP, qq[xmp --load-only -v -d file -o /dev/null "$FileNameParam" 2>\&1 |]); while () { $Line=$_; chomp $Line; if ($Line =~ /^Module title/i) { ($Junk,$FileTitle)=split (/: /,$Line,2); if ($Title ne $FileTitle) { if ($FileTitle ne "unknown") { $Title=$FileTitle; } } } elsif ($Line =~ /^Module length/i) { ($Junk,$PatternsText)=split (/: /,$Line,2); ($Patterns,$Junk)=split (/ /,$PatternsText,2); } elsif ($Line =~ /^Stored samples/i) { ($Junk,$SamplesText)=split (/: /,$Line,2); ($Samples,$Junk)=split (/ /,$SamplesText,2); } elsif ($Line =~ /^Instruments/i) { ($Junk,$SamplesText)=split (/: /,$Line,2); ($Samples,$Junk)=split (/ /,$SamplesText,2); } elsif ($Line =~ /^Channels/i) { ($Junk,$TracksText)=split (/: /,$Line,2); ($Tracks,$Junk)=split (/ /,$TracksText,2); } elsif ($Line =~ /^Estimated time/i) { ($Junk,$Length)=split (/: /,$Line,2); $Length =~ s/min/:/; $Length =~ s/s//; $Length="00:$Length"; } } $Title =~ s/'/\\'/g; close (XMP); # do the insert $InsertString="insert into trackerz values (null,'$FileName','$FileSize','$FileType','$Title','$Length','$Tracks','$Samples','$Patterns',now(),'','$MD5Sum')"; $InsertHandle=$DB->prepare($InsertString); $InsertHandle->execute; # fixup the file system (qq[chgrp music "$FileNameParam"]); system (qq[chmod 644 "$FileNameParam"]); # do the move system (qq[mv -v "$FileNameParam" /home/asylum/kmk/media/Music/tracker/]); # I like to touch files after I add them so the timestamp matches... system (qq[touch "/home/asylum/kmk/media/Music/tracker/$FileName"]); } elsif ($Command eq "rename") { # rename code here. # quick sanity check... if ($ID eq "N") { die "File not found in database!\n"; } $NewFileName=$ARGV[2]; # Rename the file first system (qq[mv -v "$FileName" "$NewFileName"]) || die "Can't rename file!"; # make things safe for MySQL $EscapedNewFileName=$NewFileName; $EscapedNewFileName =~ s/'/\\'/g; # update the db entry. $UpdateString="update trackerz set FileName='$EscapedNewFileName' where ID=$ID"; $UpdateHandle=$DB->prepare($UpdateString); $UpdateHandle->execute; } elsif ($Command eq "rm") { # file deleting code here... # quick sanity check if ($ID eq "N") { die "File not found in database!\n"; } print "Deleting ID# $ID\n"; # actually delete the file system (qq[rm -v "/home/asylum/kmk/media/tracker/$FileNameParam"]); # delete the entry from the db $DeleteString="delete from trackerz where ID=$ID"; $DeleteHandle=$DB->prepare($DeleteString); $DeleteHandle->execute; # Add to the list of trackers that I have deleted... $InsertString="insert into trackerzdeleted values ('$md5sum')"; $InsertHandle=$DB->prepare($InsertString); $InsertHandle->execute; } elsif ($Command eq "verify") { # file verify code here... # quick sanity check if ($ID eq "N") { die "File not found in database!\n"; } print "$FileNameParam: "; # Open the file and get the current size of it. # no sense in md5summing the file if it isn't even the same size. open (FH, "$FileNameParam") || die "Can't open file."; ($CurrentFileSize,$Ctime)=(stat(FH))[7,10]; close(FH); if ($CurrentFileSize != $FileSize) { print "FAILED (wrong size)\n"; } else { # grab the current md5sum of the file and compare open (TH, qq[md5sum "$FileNameParam" |]); $MD5SumText=<TH>; close (TH); chomp $MD5SumText; ($CurrentMD5Sum,$junk)=split (/ /,$MD5SumText,2); if ($CurrentMD5Sum ne $md5sum) { print "FAILED (md5)\n"; } else { print "OK\n"; } } } elsif ($Command eq "verifyall") { # file verifydir code here... # there are NO params for this command. # get the current dir # Find all files in the current dir and the dirs under it (from the db) $QueryString="select FileName,md5sum from trackerz order by FileName"; $QueryHandle=$DB->prepare($QueryString); $QueryHandle->execute; # this will be a standard md5sum file in a minute open (MD5FILE, ">/tmp/temp.kmk.trackerdb.verifyall.md5"); while (@Data=$QueryHandle->fetchrow_array) { ($FileName,$md5sum)=@Data; # write out the md5sum file print (MD5FILE "$md5sum $FileName\n"); } close (MD5FILE); # verify the files with md5sum -c open (MD5, qq[md5sum -c "/tmp/temp.kmk.trackerdb.verifyall.md5" |]); while (<MD5>) { if ($ARGV[1] !~ /q/) { print $_; } else { if ($_ !~ /OK$/) { print $_; } } } close (MD5); # get rid of the temp file system (qq[rm "/tmp/temp.kmk.trackerdb.verifyall.md5"]); } elsif ($Command eq "md5") { # file md5 code here... # quick sanity check if ($ID eq "N") { die "File not found in database!\n"; } # grab the current md5sum of the file open (TH, qq[md5sum "$FileNameParam" |]); $MD5SumText=<TH>; close (TH); chomp $MD5SumText; ($MD5Sum,$junk)=split (/ /,$MD5SumText,2); # update the db $UpdateString="update trackerz set md5sum='$MD5Sum' where ID=$ID"; $UpdateHandle=$DB->prepare($UpdateString); $UpdateHandle->execute; } else { die "Invalid command specified!"; }