doc tweaks
[id3fs.git] / sbin / id3fsd
index 983eafe..90b8739 100755 (executable)
@@ -1,25 +1,44 @@
 #!/usr/bin/perl -w
 #!/usr/bin/perl -w
-# Ian Beckwith <ianb@erislabs.net>
 #
 #
+# id3fs - a FUSE-based filesystem for browsing audio metadata
+# Copyright (C) 2010  Ian Beckwith <ianb@erislabs.net>
+#
+# 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 <http://www.gnu.org/licenses/>.
 
 
-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;
 use ID3FS::Fuse;
 use strict;
 use Getopt::Long qw(Configure);
 use ID3FS::DB;
 use ID3FS::Fuse;
+use POSIX;
+
 use vars qw($me);
 $me=($0=~/(?:.*\/)?(.*)/)[0];
 
 use vars qw($me);
 $me=($0=~/(?:.*\/)?(.*)/)[0];
 
+our $VERSION="1.00";
 my $verbose=0;
 my $help=0;
 my $dbpath=undef;
 my $verbose=0;
 my $help=0;
 my $dbpath=undef;
+my $tagdepth=undef;
 
 Configure(qw(bundling no_ignore_case));
 my $optret=GetOptions(
 
 Configure(qw(bundling no_ignore_case));
 my $optret=GetOptions(
-    "verbose|v"    => \$verbose,
-    "quiet|q"      => sub { $verbose=0; },
+    "verbose|v"    => sub { $verbose++; },
     "help|h"       => \$help,
     "database|f=s" => \$dbpath,
     "help|h"       => \$help,
     "database|f=s" => \$dbpath,
+    "t|tagdepth=s" => \$tagdepth,
+    "o=s"          => sub {;}, # silently drop options passed by mount
     );
 
 usage() if(scalar(@ARGV) != 2 || !$optret || $help);
     );
 
 usage() if(scalar(@ARGV) != 2 || !$optret || $help);
@@ -27,17 +46,35 @@ usage() if(scalar(@ARGV) != 2 || !$optret || $help);
 my $source=shift;
 my $mountpoint=shift;
 
 my $source=shift;
 my $mountpoint=shift;
 
-my $db=ID3FS::DB->new($me, $dbpath, $source);
-my $fuse=ID3FS::Fuse->new($db, $source, $mountpoint, $verbose);
+my $db=ID3FS::DB->new($me, $verbose, 0, $source, $dbpath);
+exit unless($db);
+
+my $fuse=ID3FS::Fuse->new($db, $source, $mountpoint, $verbose, $tagdepth);
+
+# disassociate from terminal
+unless($verbose)
+{
+    my $pid=fork();
+    if(defined($pid))
+    {
+       exit if($pid);   # parent
+       POSIX::setsid(); # child
+    }
+    else
+    {
+       print "$me: couldn't drop terminal: $!\n";
+    }
+}
+
 $fuse->run();
 
 sub usage
 {
 $fuse->run();
 
 sub usage
 {
-    die("Usage: $me [-vqh] [-f <dbfile>] [--] <sourcedir> <mountpoint>\n".
-       " -v\t\t\tVerbose\n".
-       " -q\t\t\tQuiet (default)\n".
-       " -h\t\t\tThis help\n".
+    die("Usage: $me [-vh] [-f <dbfile>] [-t <tagdepth>] [--] <sourcedir> <mountpoint>\n".
+       " -t|--tagdepth=NUM\tMaximum number of tags in expression (default: 10)\n" .
        " -f|--database=FILE\tPath to database file\n" .
        " -f|--database=FILE\tPath to database file\n" .
+       " -v\t\t\tVerbose (repeat for more verbosity)\n".
+       " -h\t\t\tThis help\n".
        " --\t\t\tEnd of options\n");
 }
 
        " --\t\t\tEnd of options\n");
 }
 
@@ -49,13 +86,23 @@ id3fsd - FUSE filesystem for browsing id3 tags
 
 =head1 SYNOPSIS
 
 
 =head1 SYNOPSIS
 
-B<id3fsd> [B<-vqh>] S<B<[-f >I<dbfile>]> [B<-->] I<SOURCEDIR> I<MOUNTPOINT>
+B<id3fsd> [B<-vh>] S<B<[-f >I<dbfile>]> [B<-->] I<SOURCEDIR> I<MOUNTPOINT>
 
 =head1 DESCRIPTION
 
 id3fsd provides a browsable filesystem of your music files, organised
 into sub-directories by id3 tags (or flac/ogg comments).
 
 
 =head1 DESCRIPTION
 
 id3fsd provides a browsable filesystem of your music files, organised
 into sub-directories by id3 tags (or flac/ogg comments).
 
+id3fsd allows you to construct boolean queries from a tag folksonomy
+such as:
+
+  goth/AND/decade/1980s/
+  postrock/AND/NOT/rating/terrible/
+  thrash/OR/rapmetal/AND/NOT/wears-a-red-hat/
+  prog/AND/decade/1970s/OR/psychedelia/AND/decade/1960s/
+  location/sweden/AND/screamo/AND/postrock/
+
+Multiple tags can be stored in the genre tag, separated by commas.
 An index should first be created with L<id3fs-index(1)>, then id3fsd
 can mount the files in I<SOURCEDIR> on the directory I<MOUNTPOINT>.
 
 An index should first be created with L<id3fs-index(1)>, then id3fsd
 can mount the files in I<SOURCEDIR> on the directory I<MOUNTPOINT>.
 
@@ -65,56 +112,157 @@ at I<SOURCEDIR>/B<.id3fs>.
 The resulting filesystem is read-only. Tags appear as directories,
 and files appear as symlinks to the actual files in I<SOURCEDIR>.
 
 The resulting filesystem is read-only. Tags appear as directories,
 and files appear as symlinks to the actual files in I<SOURCEDIR>.
 
-FIXME: better description, allow_others/fuse.conf, fstab, explain genre tag
+=head1 QUICKSTART
+
+To mount a view of F<~/music> on F<~/tags>:
+
+  $ mkdir ~/tags
+  $ id3fs-index ~/music
+  $ id3fsd ~/music ~/tags
+
+You may need to be in the I<fuse> group, or be root.
 
 =head1 OPTIONS
 
 =over 4
 
 
 =head1 OPTIONS
 
 =over 4
 
-=item B<-v>
+=item I<SOURCEDIR>
 
 
-Enable verbose operation.
+Directory containing actual audio files and database file F<.id3fs>
+(unless otherwise specified with B<-f>).
 
 
-=item B<-q>
+=item I<MOUNTPOINT>
 
 
-Quiet (no output). This is the default.
+Directory to mount the id3fs view of the files.
 
 
-=item B<-h>
+=item S<B<-t >I<NUM>> | S<B<--tagdepth=>I<NUM>>
 
 
-Show a short help message.
+Maximum number of tags in an expression. A query with many ANDs and
+NOTs can get quite slow. This option allows a cutoff before things get
+too slow, as well as providing some eventual limit when processes
+recurse into the filesystem. The default is 10.
 
 =item S<B<-f >I<FILE>> | S<B<--database=>I<FILE>>
 
 Use database in I<FILE>. The default is I<SOURCEDIR>/B<.id3fs>.
 
 
 =item S<B<-f >I<FILE>> | S<B<--database=>I<FILE>>
 
 Use database in I<FILE>. The default is I<SOURCEDIR>/B<.id3fs>.
 
+=item B<-v>
+
+Enable verbose operation. Repeat for more verbosity.  If verbose is
+enabled, id3fsd does not detach from the terminal.
+
+=item B<-h>
+
+Show a short help message.
+
 =item B<-->
 
 End of options.
 
 =back
 
 =item B<-->
 
 End of options.
 
 =back
 
-=head1 EXAMPLES
+=head1 FILESYSTEM LAYOUT
+
+A path in the filesystem consists of a tag query expression, followed
+by directories containing the matching files, arranged by artist and
+album.
 
 
-To mount an id3fs filesystem which indexes B<~/music/albums> on
-B<~/music/tags>:
+Example paths:
 
 
-First create the index:
+  /krautrock/AND/year/1971/
+  /krautrock/AND/year/1971/Can
+  /krautrock/AND/year/1971/Can/Tago Mago/01-Paperhouse.mp3
+  /krautrock/AND/year/1971/Can/NOALBUM/Can - Oh Yeah (Live).mp3
+  /krautrock/AND/year/1971/Can/TRACKS/01-Paperhouse.mp3
+  /krautrock/AND/year/1971/Can/TRACKS/Can - Oh Yeah (Live).mp3
+  /krautrock/AND/year/1971/NOARTIST/unknown-track.mp3
+  /krautrock/AND/year/1971/TRACKS/01-Paperhouse.mp3
 
 
-    id3fs-index -v ~/music/albums
+id3fs supports OR, AND and NOT. NOT has the highest precedence,
+followed by AND, so F<foo/OR/NOT/bar/AND/baz> is parsed as
+(foo OR ((NOT bar) AND baz)).
 
 
-If you have a large collection of music, this may take some time.
+=head2 Tags
 
 
-Then create the mountpoint:
+Tags are extracted from the B<genre> tag of audio files with
+L<id3fs-index(1)>.
 
 
-    mkdir ~/music/tags
+Within the genre frame/comment, tags are separated by commas.
 
 
-and mount the filesystem:
+Tags can have values, separated by a slash, eg I<metal/thrash>,
+I<rating/5>. Certain tags are automatically filled in from other file
+metadata, see L</"Special Tags>.
+
+=head2 Special Directories
+
+=over 4
 
 
-    id3fsd ~/music/albums ~/music/tags
+=item B<ALL>
 
 
-Then explore the tags in ~/music/tags/
+This is a special directory in the root of the filesystem, that
+provides access to all the indexed files, regardless of tags assigned.
 
 
-FIXME: fstab
+=item B<TRACKS>
+
+All tracks that match the given tag expression, whether they have an
+assigned artist and album or not.
+
+=item B<NOARTIST>
+
+Tracks matching the given expression that do not have an artist tag.
+
+=item B<NOALBUM>
+
+Tracks matching the given expression that do not have an album tag.
+
+=back
+
+=head2 Special Tags
+
+Several tags are automatically derived from other metadata in the
+audio files:
+
+=over 4
+
+=item B<year>
+
+Extracted from the B<year> or B<DATE> tag. If not found defaults to
+B<year/UNKNOWN>.
+
+=item B<decade>
+
+Also extracted from the B<year> or B<DATE> tag. If not found
+defaults to B<decade/UNKNOWN>.
+
+=item B<v1genre>
+
+If a mp3 file has an ID3V1.1 genre tag, its value is assigned to
+v1genre.
+
+=item B<audiotype>
+
+Type of audio file (mp3, ogg, flac). Always set.
+
+=back
+
+=head1 FUSE AND MOUNTING AUTOMATICALLY
+
+For others to be able to view your id3fs mount(s), you need to set the
+option B<user_allow_other> in F</etc/fuse.conf>.
+
+To mount a filesystem automatically, put an entry in F</etc/fstab>
+like:
+
+  id3fsd#/source/dir    /mount/point    defaults   0   0
+
+=head1 CAVEATS
+
+Because id3fs offers a combinatorial explosion of views of your files,
+processes recursing into the mount point will take a B<long> time to
+traverse it.
+
+Ensure your backups, cron jobs, F</etc/updatedb.conf>, etc. are
+configured to exclude the mount point.
 
 =head1 BUGS
 
 
 =head1 BUGS
 
@@ -128,19 +276,21 @@ L<id3fs-index(1)>, L<http://fuse.sourceforge.net>
 
 Ian Beckwith <ianb@erislabs.net>
 
 
 Ian Beckwith <ianb@erislabs.net>
 
+Many thanks to Aubrey Stark-Toller for help wrangling SQL.
+
 =head1 AVAILABILITY
 
 The latest version can be found at:
 
 =head1 AVAILABILITY
 
 The latest version can be found at:
 
-B<http://erislabs.net/ianb/projects/id3fs/>
+L<http://erislabs.net/ianb/projects/id3fs/>
 
 =head1 COPYRIGHT
 
 
 =head1 COPYRIGHT
 
-Copyright 2010 Ian Beckwith <ianb@erislabs.net>
+Copyright (C) 2010  Ian Beckwith <ianb@erislabs.net>
 
 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
 
 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
+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,
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,