]> diplodocus.org Git - flac-archive/blob - flac2mp3
bd39bbe0cc438b50334675c4e8f7a60a5b9ad5d5
[flac-archive] / flac2mp3
1 #!/usr/local/bin/perl
2
3 =head1 NAME
4
5 B<flac2mp3> - transcode FLAC file to MP3 files
6
7 =head1 SYNOPSIS
8
9 B<flac2mp3> [B<--lame-options> I<lame-options>] [B<-q>] [B<-v>] I<file> [...]
10
11 =head1 DESCRIPTION
12
13 B<flac2mp3> transcodes the FLAC files I<file> to MP3 files. I<file>
14 may be the kind of FLAC file B<fa-flacd> generates. That is, it
15 contains a cue sheet, one TITLE tag per track listed therein, and
16 ARTIST, ALBUM, and DATE tags.
17
18 Note that lame is retarded, and parses B<LANG> directly itself! So, in order
19 for it to transcode textual tags, you must specify the encoding in LANG, e.g.
20 LANG=en_US.utf-8
21
22 =head1 OPTIONS
23
24 =over 4
25
26 =item B<--lame-options> I<lame-options>
27
28 Pass I<lame-options> to B<lame>. This ends up being passed to the
29 shell, so feel free to take advantage of that. You'll almost
30 certainly have to put I<lame-options> in single quotes.
31
32 =item B<-q> [B<--quiet>]
33
34 Suppress status information. This option is passed along to B<flac>
35 and B<lame>.
36
37 =item B<-v> [B<--verbose>]
38
39 Print diagnostic information. This option is passed along to B<flac>
40 and B<lame>.
41
42 =back
43
44 =head1 AUTHORS
45
46 Written by Eric Gillespie <epg@pretzelnet.org>.
47
48 =cut
49
50 package epg::flac::archive::mp3;
51
52 use v5.12;
53 use warnings;
54
55 use File::Temp;
56 use FindBin;
57
58 require "$FindBin::Bin/tags.pl";
59 epg::flac::archive::tags->import(
60 qw[
61 disc_tags
62 read_tags
63 mangle_for_file_name
64 quote
65 ]);
66
67 sub flac2mp3 {
68 my %a = @_;
69
70 my @quoted_pic_options = ();
71 # (fd, picfn) = tempfile.mkstemp()
72 # os.close(fd)
73 # p = Popen(['metaflac', '--export-picture-to', picfn, unquoted_fn],
74 # stderr=PIPE)
75 # status = p.wait()
76 # stderr = ''.join(p.stderr)
77 # # Hacky check for flac with no album art
78 # if 'no PICTURE block' in stderr:
79 # # That's fine, just no picture.
80 # pass
81 # else:
82 # if status != 0:
83 # sys.stderr.write('metaflac exited %d: %s\n' % (status, stderr))
84 # return
85 # pic_options = "--ti '%s'" % picfn
86
87 # This is an old TODO; what's wrong with --ty ?
88 # TODO: Look at TDOR, TDRL, TDRC for date.
89 say(join(' ',
90 'flac',
91 '-cd',
92 quote($a{flac}),
93 '|',
94 'lame',
95 '--id3v2-only',
96 '--id3v2-latin1',
97 '--pad-id3v2-size', 0,
98 '--preset standard',
99 '--ta',
100 quote($a{artist}),
101 '--tl',
102 quote($a{album}),
103 '--tn',
104 quote($a{track}),
105 '--tt',
106 quote($a{title}),
107 '--ty',
108 quote($a{date}),
109 @quoted_pic_options,
110 (map { ('--tv', quote("TPE2=$_")) } @{$a{albumartist}}),
111 (map { ('--tv', quote("TPOS=$_")) } @{$a{discnumber}}),
112 '-',
113 quote(
114 mangle_for_file_name(
115 join(' ',
116 $a{artist},
117 $a{album},
118 (map { sprintf('%02d', $_) } @{$a{discnumber}}),
119 $a{track},
120 $a{title},
121 ))
122 . '.mp3'
123 )
124 ));
125 }
126
127 sub read_tags_metaflac {
128 my $fn = shift;
129 open(my $fh, '-|', 'metaflac', '--no-utf8-convert', '--export-tags-to=-', $fn) || die("metalfac: $!");
130 my @result = read_tags($fh);
131 if (!close($fh)) {
132 if ($! == 0) {
133 die("metaflac exited $?")
134 }
135 die("close(metaflac): $!")
136 }
137 @result
138 }
139
140 sub main {
141 for my $fn (@_) {
142 my ($tags) = read_tags_metaflac($fn);
143 my ($album, $artist, $date, $discnumber) = disc_tags($tags);
144
145 # TODO resurrect whole-disc FLAC?
146 # Stupid hack: only a single-track file should have the
147 # TRACKNUMBER tag, so use it if set for the first pass through
148 # the loop. At the end of the loop, we'll set $track for the
149 # next run, so this continues to work for multi-track files.
150 # if track == None:
151 # track = 1
152 # else:
153 # track = int(track)
154 {
155 my $tracknumber = epg::flac::archive::tags::one(TRACKNUMBER => $tags);
156 my $title = epg::flac::archive::tags::one(TITLE => $tags);
157 # TODO restore PARTNUMBER and VERSION net time i need them
158 flac2mp3(
159 artist => $artist,
160 album => $album,
161 date => $date,
162 discnumber => $discnumber,
163 track => $tracknumber,
164 title => $title,
165 flac => $fn,
166 )
167 }
168 }
169
170 return 0;
171 }
172
173 if (!caller) {
174 exit(main(@ARGV))
175 }
176
177 1;