#!/usr/bin/perl -w # # 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'; # FIXME: remove use strict; use Getopt::Long qw(Configure); use ID3FS::DB; use ID3FS::Fuse; use POSIX; use vars qw($me); $me=($0=~/(?:.*\/)?(.*)/)[0]; our $VERSION="1.00"; my $verbose=0; my $help=0; my $dbpath=undef; my $tagdepth=undef; Configure(qw(bundling no_ignore_case)); my $optret=GetOptions( "verbose|v" => sub { $verbose++; }, "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); my $source=shift; my $mountpoint=shift; 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 { die("Usage: $me [-vh] [-f ] [-t ] [--] \n". " -t|--tagdepth=NUM\tMaximum number of tags in expression (default: 6)\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"); } __END__ =head1 NAME id3fsd - FUSE filesystem for browsing id3 tags =head1 SYNOPSIS B [B<-vh>] SI]> [B<-->] I I =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, then id3fsd can mount the files in I on the directory I. If not explicitly specified (with B<-f>), the index is searched for at I/B<.id3fs>. The resulting filesystem is read-only. Tags appear as directories, and files appear as symlinks to the actual files in I. =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 group, or be root. =head1 OPTIONS =over 4 =item I Directory containing actual audio files and database file F<.id3fs> (unless otherwise specified with B<-f>). =item I Directory to mount the id3fs view of the files. =item SI> | SI> 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 6. =item SI> | SI> Use database in I. The default is I/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 =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. Example paths: /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 supports OR, AND and NOT. NOT has the highest precedence, followed by AND, so F is parsed as (foo OR ((NOT bar) AND baz)). =head2 Tags Tags are extracted from the B tag of audio files with L. Within the genre frame/comment, tags are separated by commas. Tags can have values, separated by a slash, eg I, I. Certain special tags are automatically filled in from other file metadata. =head2 Special Tags The following tags are automatically derived from other metadata in the audio files: =over 4 =item B Extracted from the B or B tag. If not found defaults to B. =item B Also extracted from the B or B tag. If not found defaults to B. =item B If a mp3 file has an ID3V1.1 genre tag, its value is assigned to v1genre. =item B Type of audio file (mp3, ogg, flac). Always set. =back =head2 Special Directories =over 4 =item B All tracks that match the given tag expression, whether they have an assigned artist and album or not. =item B Tracks matching the given expression that do not have an artist tag. =item B Tracks matching the given expression that do not have an album tag. =item B This is a special directory in the root of the filesystem, that provides access to all the indexed files, regardless of tags assigned. =back =head1 FUSE AND MOUNTING AUTOMATICALLY For others to be able to view your id3fs mount(s), you need to set the option B in F. To mount a filesystem automatically, put an entry in F 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 time to traverse it. Ensure your backups, cron jobs, F, etc. are configured to exclude the mount point. =head1 BUGS Please report any found to ianb@erislabs.net =head1 SEE ALSO L, L =head1 AUTHOR Ian Beckwith Many thanks to Aubrey Stark-Toller for help wrangling SQL. =head1 AVAILABILITY The latest version can be found at: L =head1 COPYRIGHT 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 . =cut