3 # id3fs - a FUSE-based filesystem for browsing audio metadata
4 # Copyright (C) 2010 Ian Beckwith <ianb@erislabs.net>
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.
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.
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/>.
19 use lib '/home/ianb/projects/id3fs/id3fs/lib'; # FIXME: remove
21 use Getopt::Long qw(Configure);
24 $me=($0=~/(?:.*\/)?(.*)/)[0];
28 my ($artist, $album, $track, $tracknum, $year, $v1genre, $comment,
29 $delete_artist, $delete_album, $delete_track, $delete_tracknum,
30 $delete_year, $delete_v1genre, $delete_comment, $delete_all,
31 $delete_genre, $genre, $add_tags, $delete_tags, @replace_tags);
33 Configure(qw(no_ignore_case));
34 my $optret=GetOptions(
35 "verbose|v" => \$verbose,
37 "artist|a=s" => \$artist,
38 "album|l=s" => \$album,
39 "song|s=s" => \$track,
40 "tracknum|n=s" => \$tracknum,
42 "v1genre|1=s" => \$v1genre,
43 "comment|c=s" => \$comment,
44 "delete-artist|A" => \$delete_artist,
45 "delete-album|L" => \$delete_album,
46 "delete-song|S" => \$delete_track,
47 "delete-tracknum|N" => \$delete_tracknum,
48 "delete-year|Y" => \$delete_year,
49 "delete-v1genre|0" => \$delete_v1genre,
50 "delete-comment|C" => \$delete_comment,
51 "delete|delete-all|D" => \$delete_all,
52 "delete-genre|delete-all-tags|G" => \$delete_genre,
53 "genre|g|replace-all-tags|R=s" => \$genre,
54 "add-tags|tags|t=s" => \$add_tags,
55 "delete-tags|T=s" => \$delete_tags,
56 "replace-tags|r=s{2}" => \@replace_tags,
59 usage() if(!@ARGV || !$optret || $help);
61 while(my $filename=shift @ARGV)
65 warn("$me: $filename: not found\n");
68 my $file=ID3FS::AudioFile->new($filename);
70 $changes = do_deletes($file);
71 $changes += do_adds($file);
85 $file->delete_artist() if($delete_artist);
86 $file->delete_album() if($delete_album);
87 $file->delete_track() if($delete_track);
88 $file->delete_tracknum() if($delete_tracknum);
89 $file->delete_year() if($delete_year);
90 $file->delete_v1genre() if($delete_v1genre);
91 $file->delete_comment() if($delete_comment);
92 $file->delete_all() if($delete_all);
93 $file->delete_genre() if($delete_genre);
94 $file->delete_tags($delete_tags) if($delete_tags);
95 if(@replace_tags && $replace_tags[0])
97 $file->delete_tags($replace_tags[0]);
100 return($delete_artist || $delete_album || $delete_track ||
101 $delete_tracknum || $delete_year || $delete_v1genre ||
102 $delete_comment || $delete_all || $delete_genre ||
103 $delete_tags || (@replace_tags && $replace_tags[0]));
109 $file->artist($artist) if($artist);
110 $file->album($album) if($album);
111 $file->track($track) if($track);
112 $file->tracknum($tracknum) if($tracknum);
113 $file->year($year) if($year);
114 $file->v1genre($v1genre) if($v1genre);
115 $file->comment($comment) if($comment);
116 $file->genre($genre) if($genre);
117 $file->add_tags($add_tags) if($add_tags);
118 if(@replace_tags && $replace_tags[0])
120 $file->add_tags($replace_tags[1]);
123 return(defined($artist) || defined($album) || defined($track) ||
124 defined($tracknum) || defined($year) || defined($v1genre) ||
125 defined($comment) || defined($genre) || defined($add_tags) ||
126 (@replace_tags && defined($replace_tags[1])));
139 my $artist=$file->artist();
140 my $album=$file->album();
141 my $track=$file->track();
142 my $tracknum=$file->tracknum();
143 my $year=$file->year();
144 my $comment=$file->comment();
145 my $v1genre=$file->v1genre();
146 my @tags=$file->tags();
149 print $file->path(), ":\n";
150 print "tracknum: $tracknum\n" if($tracknum);
151 print "artist: $artist\n" if($artist);
152 print "album: $album\n" if($album);
153 print "song: $track\n" if($track);
154 print "year: $year\n" if($year);
155 print "v1genre: $v1genre\n" if($v1genre);
156 print "comment: $comment\n" if($comment);
160 my @fields=($file->path(), $tracknum, $artist, $album, $track,
161 $year, $v1genre, $comment);
162 @fields=map { defined($_) ? $_ : ""; } @fields;
163 print join(':', @fields), "\n";
166 print "tags:", join(", ", @tags), "\n";
173 die("Usage: $me [-vhALSNY0CDG] [-a ARTIST] [-l ALBUM] [-s SONG] [-n TRACKNUM] FILES...\n".
174 " $me [-y YEAR] [-g GENRE] [-1 V1GENRE] [-c COMMENT] [--] FILES...\n".
175 " $me [-t TAGS,TO,ADD] [-T TAGS,TO,DELETE] FILES...\n".
176 " $me [-r TAGS,TO,DELETE TAGS,TO,ADD] [-R TAGS,TO,OVERWRITE,WITH] FILES...\n".
177 "With no options, displays current info in tag\n".
179 " -a|--artist=ARTIST Set artist\n".
180 " -l|--album=ALBUM Set album\n".
181 " -s|--song=SONG Set song\n".
182 " -n|--tracknum=NUM Set tracknum\n".
183 " -y|--year=NUM Set year\n".
184 " -1|--v1genre=GENRE Set ID3v1 genre\n".
185 " -c|--comment=COMMENT Set comment\n".
186 " -A|--delete-artist Delete artist\n".
187 " -L|--delete-album Delete album\n".
188 " -S|--delete-song Delete song\n".
189 " -N|--delete-tracknum Delete tracknum\n".
190 " -Y|--delete-year Delete year\n".
191 " -0|--delete-v1genre Delete ID3v1 genre\n".
192 " -C|--delete-comment Delete comment\n".
193 " -D|--delete|delete-all Delete entire ID3 tag\n".
194 " -G|--delete-genre|--delete-all-tags Delete all tags stored in genre\n".
195 " -g|-R|replace-all-tags|--genre=GENRE Replace all tags in genre tag\n".
196 " -t|--add-tags|tags=TAG1,TAG2 Add tags to genre tag, merging with existing ones\n".
197 " -T|--delete-tags=TAG1,TAG2 Delete tags from genre\n".
198 " -r|--replace-tags TAGS1 TAGS2 Replace TAGS1 in genre with TAGS2\n".
199 " -v|--verbose Verbose display\n".
200 " -h|--help This help\n".
201 " -- End of options\n");
208 id3fs-tag - Add files to id3fs index
212 B<id3fs-tag> [B<-lvh>] S<[B<-d >I<basedir>]> S<[B<-f >I<dbpath>]> S<[B<-e >I<mp3,ogg,flac>]> [B<-->] [I<DIR>...]
216 Extracts id3 tags from mp3 files (and comment tags from ogg and flac
217 files) and adds them to a sqlite database, ready for mounting
224 =item B<-l> | B<--list>
226 List tags in use in specified database.
228 =item S<B<-d >I<PATH>> | S<B<--dir=>I<PATH>>
230 Specify base directory of source files. All files will be indexed
231 relative to this point.
233 If not specified, defaults to the first non-option argument on the
234 command line. Note that to avoid ambiguities, if more than one
235 directory is specified on the command line, the base directory must
236 be specified explicitly.
238 All files indexed must be under the base directory.
240 =item S<B<-f >I<FILE>> | S<B<--database=>I<FILE>>
242 Database file to use. If not specified, defaults to
243 a hidden file called B<".id3fs"> under the base directory.
245 =item S<B<-e >I<EXT1,EXT2>> | S<B<--extensions=>I<EXT1,EXT2>>
247 File extensions to consider when indexing.
248 Defaults to B<.mp3>, B<.ogg> and B<.flac>.
252 Enable verbose operation.
256 Show a short help message.
266 Index all files in the current directory:
270 Index current directory, printing each subdirectory as it recurses
275 Just index some sub-directories:
277 id3fs-tag -d . dir1 dir2
279 Store the database in a custom location:
281 id3fs-tag -f ~/.id3fs/index.sqlite .
283 Only index .mp3 and .flac files:
285 id3fs-tag -e mp3,flac .
289 Please report any found to ianb@erislabs.net
293 L<id3fsd(8)>, L<MP3::Tag>, L<Audio::Flac::Header>, L<Ogg::Vorbis::Header>
297 Ian Beckwith <ianb@erislabs.net>
299 Many thanks to Aubrey Stark-Toller for help wrangling SQL.
303 The latest version can be found at:
305 L<http://erislabs.net/ianb/projects/id3fs/>
309 Copyright (C) 2010 Ian Beckwith <ianb@erislabs.net>
311 This program is free software: you can redistribute it and/or modify
312 it under the terms of the GNU General Public License as published by
313 the Free Software Foundation, either version 3 of the License, or
314 (at your option) any later version.
316 This program is distributed in the hope that it will be useful,
317 but WITHOUT ANY WARRANTY; without even the implied warranty of
318 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
319 GNU General Public License for more details.
321 You should have received a copy of the GNU General Public License
322 along with this program. If not, see <http://www.gnu.org/licenses/>.