61b70682f24847a96117608669078045015e71dc
[id3fs.git] / sbin / id3fsd
1 #!/usr/bin/perl -w
2 #
3 # id3fs - a FUSE-based filesystem for browsing audio metadata
4 # Copyright (C) 2010  Ian Beckwith <ianb@erislabs.net>
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19 use lib '/home/ianb/projects/id3fs/id3fs/lib'; # FIXME: remove
20 use strict;
21 use Getopt::Long qw(Configure);
22 use ID3FS::DB;
23 use ID3FS::Fuse;
24 use POSIX;
25
26 use vars qw($me);
27 $me=($0=~/(?:.*\/)?(.*)/)[0];
28
29 our $VERSION="1.00";
30 my $verbose=0;
31 my $help=0;
32 my $dbpath=undef;
33 my $tagdepth=undef;
34
35 Configure(qw(bundling no_ignore_case));
36 my $optret=GetOptions(
37     "verbose|v"    => sub { $verbose++; },
38     "help|h"       => \$help,
39     "database|f=s" => \$dbpath,
40     "t|tagdepth=s" => \$tagdepth,
41     "o=s"          => sub {;}, # silently drop options passed by mount
42     );
43
44 usage() if(scalar(@ARGV) != 2 || !$optret || $help);
45
46 my $source=shift;
47 my $mountpoint=shift;
48
49 my $db=ID3FS::DB->new($me, $verbose, 0, $source, $dbpath);
50 exit unless($db);
51
52 my $fuse=ID3FS::Fuse->new($db, $source, $mountpoint, $verbose, $tagdepth);
53
54 # disassociate from terminal
55 unless($verbose)
56 {
57     my $pid=fork();
58     if(defined($pid))
59     {
60         exit if($pid);   # parent
61         POSIX::setsid(); # child
62     }
63     else
64     {
65         print "$me: couldn't drop terminal: $!\n";
66     }
67 }
68
69 $fuse->run();
70
71 sub usage
72 {
73     die("Usage: $me [-vh] [-f <dbfile>] [-t <tagdepth>] [--] <sourcedir> <mountpoint>\n".
74         " -t|--tagdepth=NUM\tMaximum number of tags in expression (default: 10)\n" .
75         " -f|--database=FILE\tPath to database file\n" .
76         " -v\t\t\tVerbose (repeat for more verbosity)\n".
77         " -h\t\t\tThis help\n".
78         " --\t\t\tEnd of options\n");
79 }
80
81 __END__
82
83 =head1 NAME
84
85 id3fsd - FUSE filesystem for browsing id3 tags
86
87 =head1 SYNOPSIS
88
89 B<id3fsd> [B<-vh>] S<B<[-f >I<dbfile>]> [B<-->] I<SOURCEDIR> I<MOUNTPOINT>
90
91 =head1 DESCRIPTION
92
93 id3fsd provides a browsable filesystem of your music files, organised
94 into sub-directories by id3 tags (or flac/ogg comments).
95
96 id3fsd allows you to construct boolean queries from a tag folksonomy
97 such as:
98
99   goth/AND/decade/1980s/
100   postrock/AND/NOT/rating/terrible/
101   thrash/OR/rapmetal/AND/NOT/wears-a-red-hat/
102   prog/AND/decade/1970s/OR/psychedelia/AND/decade/1960s/
103   location/sweden/AND/screamo/AND/postrock/
104
105 Multiple tags can be stored in the genre tag, separated by commas.
106 An index should first be created with L<id3fs-index(1)>, then id3fsd
107 can mount the files in I<SOURCEDIR> on the directory I<MOUNTPOINT>.
108
109 If not explicitly specified (with B<-f>), the index is searched for
110 at I<SOURCEDIR>/B<.id3fs>.
111
112 The resulting filesystem is read-only. Tags appear as directories,
113 and files appear as symlinks to the actual files in I<SOURCEDIR>.
114
115 =head1 QUICKSTART
116
117 To mount a view of F<~/music> on F<~/tags>:
118
119   $ mkdir ~/tags
120   $ id3fs-index ~/music
121   $ id3fsd ~/music ~/tags
122
123 You may need to be in the I<fuse> group, or be root.
124
125 =head1 OPTIONS
126
127 =over 4
128
129 =item I<SOURCEDIR>
130
131 Directory containing actual audio files and database file F<.id3fs>
132 (unless otherwise specified with B<-f>).
133
134 =item I<MOUNTPOINT>
135
136 Directory to mount the id3fs view of the files.
137
138 =item S<B<-t >I<NUM>> | S<B<--tagdepth=>I<NUM>>
139
140 Maximum number of tags in an expression. A query with many ANDs and
141 NOTs can get quite slow. This option allows a cutoff before things get
142 too slow, as well as providing some eventual limit when processes
143 recurse into the filesystem. The default is 10.
144
145 =item S<B<-f >I<FILE>> | S<B<--database=>I<FILE>>
146
147 Use database in I<FILE>. The default is I<SOURCEDIR>/B<.id3fs>.
148
149 =item B<-v>
150
151 Enable verbose operation. Repeat for more verbosity.  If verbose is
152 enabled, id3fsd does not detach from the terminal.
153
154 =item B<-h>
155
156 Show a short help message.
157
158 =item B<-->
159
160 End of options.
161
162 =back
163
164 =head1 FILESYSTEM LAYOUT
165
166 A path in the filesystem consists of a tag query expression, followed
167 by directories containing the matching files, arranged by artist and
168 album.
169
170 Example paths:
171
172   /krautrock/AND/year/1971/
173   /krautrock/AND/year/1971/Can
174   /krautrock/AND/year/1971/Can/Tago Mago/01-Paperhouse.mp3
175   /krautrock/AND/year/1971/Can/NOALBUM/Can - Oh Yeah (Live).mp3
176   /krautrock/AND/year/1971/Can/TRACKS/01-Paperhouse.mp3
177   /krautrock/AND/year/1971/Can/TRACKS/Can - Oh Yeah (Live).mp3
178   /krautrock/AND/year/1971/NOARTIST/unknown-track.mp3
179   /krautrock/AND/year/1971/TRACKS/01-Paperhouse.mp3
180
181 =head2 Tags
182
183 Tags are extracted from the B<genre> tag of audio files with
184 L<id3fs-index(1)>.
185
186 Within the genre frame/comment, tags are separated by commas.
187
188 Tags can have values, separated by a slash, eg I<metal/thrash>,
189 I<rating/5>. Certain tags are automatically filled in from other file
190 metadata, see L</"Special Tags>.
191
192 =head2 Special Directories
193
194 =over 4
195
196 =item B<ALL>
197
198 This is a special directory in the root of the filesystem, that
199 provides access to all the indexed files, regardless of tags assigned.
200
201 =item B<TRACKS>
202
203 All tracks that match the given tag expression, whether they have an
204 assigned artist and album or not.
205
206 =item B<NOARTIST>
207
208 Tracks matching the given expression that do not have an artist tag.
209
210 =item B<NOALBUM>
211
212 Tracks matching the given expression that do not have an album tag.
213
214 =back
215
216 =head2 Special Tags
217
218 Several tags are automatically derived from other metadata in the
219 audio files:
220
221 =over 4
222
223 =item B<year>
224
225 Extracted from the B<year> or B<DATE> tag. If not found defaults to
226 B<year/UNKNOWN>.
227
228 =item B<decade>
229
230 Also extracted from the B<year> or B<DATE> tag. If not found
231 defaults to B<decade/UNKNOWN>.
232
233 =item B<v1genre>
234
235 If a mp3 file has an ID3V1.1 genre tag, its value is assigned to
236 v1genre.
237
238 =item B<audiotype>
239
240 Type of audio file (mp3, ogg, flac). Always set.
241
242 =back
243
244 =head1 FUSE AND MOUNTING AUTOMATICALLY
245
246 For others to be able to view your id3fs mount(s), you need to set the
247 option B<user_allow_other> in F</etc/fuse.conf>.
248
249 To mount a filesystem automatically, put an entry in F</etc/fstab>
250 like:
251
252   id3fsd#/source/dir    /mount/point    defaults   0   0
253
254 =head1 CAVEATS
255
256 Because id3fs offers a combinatorial explosion of views of your files,
257 processes recursing into the mount point will take a B<long> time to
258 traverse it.
259
260 Ensure your backups, cron jobs, F</etc/updatedb.conf>, etc. are
261 configured to exclude the mount point.
262
263 =head1 BUGS
264
265 Please report any found to ianb@erislabs.net
266
267 =head1 SEE ALSO
268
269 L<id3fs-index(1)>, L<http://fuse.sourceforge.net>
270
271 =head1 AUTHOR
272
273 Ian Beckwith <ianb@erislabs.net>
274
275 Many thanks to Aubrey Stark-Toller for help wrangling SQL.
276
277 =head1 AVAILABILITY
278
279 The latest version can be found at:
280
281 L<http://erislabs.net/ianb/projects/id3fs/>
282
283 =head1 COPYRIGHT
284
285 Copyright (C) 2010  Ian Beckwith <ianb@erislabs.net>
286
287 This program is free software: you can redistribute it and/or modify
288 it under the terms of the GNU General Public License as published by
289 the Free Software Foundation, either version 3 of the License, or
290 (at your option) any later version.
291
292 This program is distributed in the hope that it will be useful,
293 but WITHOUT ANY WARRANTY; without even the implied warranty of
294 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
295 GNU General Public License for more details.
296
297 You should have received a copy of the GNU General Public License
298 along with this program.  If not, see <http://www.gnu.org/licenses/>.
299
300 =cut