X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=bin%2Fid3fs-index;h=7f0c17ca67464afd28edd3f359334c8553b20a52;hb=198047fe7da462f486e7da3a751ecdea8d285750;hp=62a631e9f0d8b82b46e97a30ccabfe49e1858f69;hpb=da6467fdae84d8f5da26a681537d887a63e18aec;p=id3fs.git diff --git a/bin/id3fs-index b/bin/id3fs-index index 62a631e..7f0c17c 100755 --- a/bin/id3fs-index +++ b/bin/id3fs-index @@ -1,8 +1,22 @@ #!/usr/bin/perl -w -# Ian Beckwith # +# id3fs - a FUSE-based filesystem for browsing audio metadata +# Copyright (C) 2010 Ian Beckwith +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . -use lib '/home/ianb/projects/id3fs/id3fs/lib'; +use lib '/home/ianb/projects/id3fs/id3fs/lib'; # FIXME: remove use strict; use Getopt::Long qw(Configure); use ID3FS::DB; @@ -14,31 +28,70 @@ my $verbose=0; my $help=0; my $basedir=undef; my $dbpath=undef; +my $list=0; +my $init=0; +my @extensions=qw(mp3 flac ogg); +my $files_pruned; -my @extensions=qw(mp3); # ogg flac); # FIXME Configure(qw(bundling no_ignore_case)); my $optret=GetOptions( "verbose|v" => \$verbose, "quiet|q" => sub { $verbose=0; }, "help|h" => \$help, - "basedir|d=s" => \$basedir, - "database|db=s" => \$dbpath, + "dir|d=s" => \$basedir, + "database|f=s" => \$dbpath, "extensions|e=s" => sub { @extensions=split(/\s+|\s*,\s*/, $_[1]); }, + "list|l" => \$list, ); +if($list && !@ARGV) +{ + push(@ARGV, "."); +} usage() if(!@ARGV || !$optret || $help); +$init=1 unless($list); -if(@ARGV > 1 && !defined($basedir)) +unless(defined($basedir) && defined($dbpath)) { - die("$me: --basedir must be specified if multiple paths are supplied\n"); + $basedir=ID3FS::DB::find_db($me, $init, @ARGV); + exit unless($basedir); + my $absbase=Cwd::abs_path($basedir); + for my $dir (@ARGV) + { + if(Cwd::abs_path($dir) !~ /^\Q$absbase\E/) + { + die("$me: $dir: must be under basedir $absbase - use --basedir to specify\n"); + } + } } +my $db=ID3FS::DB->new($me, $verbose, $init, $basedir, $dbpath); +exit unless($db); -my $db=ID3FS::DB->new($me, $dbpath, $basedir, $ARGV[0]); -$db->last_update(time()); - -while(my $path=shift) +if($list) { - File::Find::find( {wanted => \&wanted, follow => 1, no_chdir => 1}, $path); + list_tags($db); +} +else +{ + $db->last_update(time()); + my $base=$db->base_dir(); + my $abs_base=Cwd::abs_path($base); + while(my $path=shift) + { + if(Cwd::abs_path($path) !~ /^$abs_base/) + { + print "$me: $path is outside $base, skipping\n"; + } + File::Find::find( {wanted => \&wanted, follow => 1, no_chdir => 1}, $path); + } + my $directories_pruned=$db->prune_directories(); + if($files_pruned || $directories_pruned) + { + print "$me: removing data from pruned files\n" if $verbose; + $db->remove_unused(); + } + print "$me: analyzing db\n" if $verbose; + $db->analyze(); } sub wanted @@ -48,6 +101,7 @@ sub wanted if(-d) { print("$_\n") if $verbose; + prune($_); } elsif(-f && scalar(grep({ $ext eq lc($_);} @extensions))) { @@ -56,28 +110,79 @@ sub wanted } } + +sub prune +{ + my $dir=shift; + $dir=Cwd::abs_path($dir); + return unless(opendir(DIR, $dir)); + my $base=Cwd::abs_path($db->base_dir()); + $dir=~s/^$base\/?//; + my @oldfiles=$db->files_in($dir); + my @newfiles=grep { !/^\.\.?$/; } readdir(DIR); + closedir(DIR); + @oldfiles=sort @oldfiles; + @newfiles=sort @newfiles; + my %hash; + @hash{@newfiles}=(); + for my $file (@oldfiles) + { + unless(exists($hash{$file})) + { + $files_pruned=1; + $db->unindex($dir, $file); + } + } +} + +sub list_tags +{ + my($db)=@_; + my @baretags=$db->bare_tags(); + my $valtags=$db->tags_with_values(); + if(@baretags) + { + print "BARE TAGS\n"; + print join(', ', sort @baretags), "\n\n"; + } + if(keys(%$valtags)) + { + print "TAGS WITH VALUES\n"; + for my $key (sort keys %$valtags) + { + print "$key: ", join(', ', sort(@{$valtags->{$key}})), "\n"; + } + } +} + sub usage { - die("Usage: $me [-v] [-q] [-h] [--] file...\n". - " -v\tVerbose\n". - " -q\tQuiet (default)\n". - " -h\tThis help\n". - " --\tEnd of options\n"); + die("Usage: $me [-vqh] [-d basedir] [-f dbpath] [-e mp3,ogg,flac] [--] DIR...\n". + " -v|--verbose\t\t\tVerbose\n". + " -q|--quiet\t\t\tQuiet (default)\n". + " -d|--dir=PATH\t\t\tBase directory of source files (default: ARGV[0])\n". + " -f|--database=FILE\t\tPath to database file (default: basedir/.id3fs)\n". + " -e|--extensions=EXT1,EXT2\tFile extensions to index (default: mp3, ogg, flac)\n". + " -h|--help\t\t\tThis help\n". + " --\t\t\t\tEnd of options\n"); } __END__ - =head1 NAME -program - description +id3fs-index - Add files to id3fs index =head1 SYNOPSIS -B<> [I<-v>] [I<-q>] [I<-h>] [I...] +B [B<-vqh>] S<[B<-d >I]> S<[B<-f >I]> S<[B<-e >I]> [B<-->] [I...] =head1 DESCRIPTION +Extracts id3 tags from mp3 files (and comment tags from ogg and flac +files) and adds them to a sqlite database, ready for mounting +with L. + =head1 OPTIONS =over 4 @@ -90,6 +195,28 @@ Enable verbose operation. Quiet (no output). This is the default. +=item SI> | SI> + +Specify base directory of source files. All files will be indexed +relative to this point. + +If not specified, defaults to the first non-option argument on the +command line. Note that to avoid ambiguities, if more than one +directory is specified on the command line, the base directory must +be specified explicitly. + +All files indexed must be under the base directory. + +=item SI> | SI> + +Database file to use. If not specified, defaults to +a hidden file called B<".id3fs"> under the base directory. + +=item SI> | SI> + +File extensions to consider when indexing. +Defaults to B<.mp3>, B<.ogg> and B<.flac>. + =item B<-h> Show a short help message. @@ -100,18 +227,37 @@ End of options. =back -=head1 FILES +=head1 EXAMPLES + +Index all files in the current directory: + + id3fs-index . + +Index current directory, printing each subdirectory as it recurses +into it: + + id3fs-index -v . -=head1 ENVIRONMENT +Just index some sub-directories: -=head1 DIAGNOSTICS + id3fs-index -d . dir1 dir2 + +Store the database in a custom location: + + id3fs-index -f ~/.id3fs/index.sqlite . + +Only index .mp3 and .flac files: + + id3fs-index -e mp3,flac . =head1 BUGS -None known. Please report any found to ianb@erislabs.net +Please report any found to ianb@erislabs.net =head1 SEE ALSO +L + =head1 AUTHOR Ian Beckwith