mirror of
https://github.com/moex3/flac2mp3.pl
synced 2024-11-22 03:54:15 -05:00
Compare commits
No commits in common. "ccc5ba6af9895a58ada0a9a867a14567f46e1f20" and "f75c7fa58239de569dcf032839c91e33c860a7d1" have entirely different histories.
ccc5ba6af9
...
f75c7fa582
126
flac2mp3.pl
126
flac2mp3.pl
@ -9,7 +9,6 @@ use File::Basename;
|
|||||||
my $opt_no_genre;
|
my $opt_no_genre;
|
||||||
my $opt_comment;
|
my $opt_comment;
|
||||||
my $opt_catid;
|
my $opt_catid;
|
||||||
my $opt_rg;
|
|
||||||
|
|
||||||
# TODO fill this out
|
# TODO fill this out
|
||||||
my %genreMap = (
|
my %genreMap = (
|
||||||
@ -19,7 +18,6 @@ my %genreMap = (
|
|||||||
|
|
||||||
# this is a godsent page
|
# this is a godsent page
|
||||||
# https://wiki.hydrogenaud.io/index.php?title=Tag_Mapping
|
# https://wiki.hydrogenaud.io/index.php?title=Tag_Mapping
|
||||||
# https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html
|
|
||||||
# a lot of this may not work
|
# a lot of this may not work
|
||||||
# TODO escape potential 's
|
# TODO escape potential 's
|
||||||
my %idLookup = (
|
my %idLookup = (
|
||||||
@ -45,7 +43,6 @@ my %idLookup = (
|
|||||||
#performer => 'TMCL', # This produces some really weird tags
|
#performer => 'TMCL', # This produces some really weird tags
|
||||||
producer => 'TIPL=producer',
|
producer => 'TIPL=producer',
|
||||||
publisher => 'TPUB',
|
publisher => 'TPUB',
|
||||||
organization => 'TPUB',
|
|
||||||
label => 'TPUB',
|
label => 'TPUB',
|
||||||
remixer => 'TPE4',
|
remixer => 'TPE4',
|
||||||
discnumber => ['TPOS', sub {
|
discnumber => ['TPOS', sub {
|
||||||
@ -65,33 +62,22 @@ my %idLookup = (
|
|||||||
totaltracks => undef,
|
totaltracks => undef,
|
||||||
tracktotal => undef,
|
tracktotal => undef,
|
||||||
#date => 'TDRC', # This is for id3v2.4
|
#date => 'TDRC', # This is for id3v2.4
|
||||||
#date => 'TYER',
|
date => 'TYER',
|
||||||
date => [undef, sub {
|
|
||||||
my $t = shift;
|
|
||||||
my $date = $t->{date};
|
|
||||||
if (length($date) == 4) { # Only year
|
|
||||||
return "TYER=$date";
|
|
||||||
}
|
|
||||||
if (!($date =~ m/^\d{4}\.\d{2}\.\d{2}$/)) {
|
|
||||||
print("Date format unknown: $date\n");
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
$date =~ s/\./-/g;
|
|
||||||
return "TDRL=$date"; # Release date
|
|
||||||
}],
|
|
||||||
originaldate => 'TDOR', # Also for 2.4 only
|
originaldate => 'TDOR', # Also for 2.4 only
|
||||||
'release date' => 'TDOR', # Also for 2.4 only
|
|
||||||
isrc => 'TSRC',
|
isrc => 'TSRC',
|
||||||
barcode => 'TXXX=BARCODE',
|
barcode => 'TXXX=BARCODE',
|
||||||
catalog => ['TXXX=CATALOGNUMBER', sub { return tagmap_catalogid(shift, 'catalog'); } ],
|
catalog => ['TXXX=CATALOGNUMBER', sub { return tagmap_catalogid(shift, 'catalog'); } ],
|
||||||
catalognumber => ['TXXX=CATALOGNUMBER', sub { return tagmap_catalogid(shift, 'catalognumber'); } ],
|
catalognumber => ['TXXX=CATALOGNUMBER', sub { return tagmap_catalogid(shift, 'catalognumber'); } ],
|
||||||
catalogid => ['TXXX=CATALOGNUMBER', sub { return tagmap_catalogid(shift, 'catalogid'); } ],
|
catalogid => ['TXXX=CATALOGNUMBER', sub { return tagmap_catalogid(shift, 'catalogid'); } ],
|
||||||
labelno => ['TXXX=CATALOGNUMBER', sub { return tagmap_catalogid(shift, 'labelno'); } ],
|
|
||||||
'encoded-by' => 'TENC',
|
'encoded-by' => 'TENC',
|
||||||
encoder => 'TSSE',
|
encoder => 'TSSE',
|
||||||
encoding => 'TSSE',
|
encoding => 'TSSE',
|
||||||
'encoder settings' => 'TSSE',
|
'encoder settings' => 'TSSE',
|
||||||
media => 'TMED',
|
media => 'TMED',
|
||||||
|
replaygain_album_gain => 'TXXX=REPLAYGAIN_ALBUM_GAIN',
|
||||||
|
replaygain_album_peak => 'TXXX=REPLAYGAIN_ALBUM_PEAK',
|
||||||
|
replaygain_track_gain => 'TXXX=REPLAYGAIN_TRACK_GAIN',
|
||||||
|
replaygain_track_peak => 'TXXX=REPLAYGAIN_TRACK_PEAK',
|
||||||
genre => ['TCON', sub {
|
genre => ['TCON', sub {
|
||||||
return undef if ($opt_no_genre);
|
return undef if ($opt_no_genre);
|
||||||
|
|
||||||
@ -111,26 +97,9 @@ my %idLookup = (
|
|||||||
}],
|
}],
|
||||||
copyright => 'TCOP',
|
copyright => 'TCOP',
|
||||||
language => 'TLAN',
|
language => 'TLAN',
|
||||||
#replaygain_album_peak => 'TXXX=REPLAYGAIN_ALBUM_PEAK',
|
|
||||||
#replaygain_album_gain => 'TXXX=REPLAYGAIN_ALBUM_GAIN',
|
|
||||||
replaygain_track_gain => sub {
|
|
||||||
return undef if (!$opt_rg);
|
|
||||||
shift->{replaygain_track_gain} =~ /^(-?\d+\.\d+) dB$/;
|
|
||||||
my $gain_db = $1;
|
|
||||||
exit(1) if ($gain_db eq "");
|
|
||||||
return "--replaygain-accurate --gain $gain_db";
|
|
||||||
},
|
|
||||||
|
|
||||||
#replaygain_album_gain => 'TXXX=REPLAYGAIN_ALBUM_GAIN',
|
|
||||||
#replaygain_album_peak => 'TXXX=REPLAYGAIN_ALBUM_PEAK',
|
|
||||||
#replaygain_track_gain => 'TXXX=REPLAYGAIN_TRACK_GAIN',
|
|
||||||
#replaygain_track_peak => 'TXXX=REPLAYGAIN_TRACK_PEAK',
|
|
||||||
script => 'TXXX=SCRIPT',
|
script => 'TXXX=SCRIPT',
|
||||||
lyrics => 'USLT',
|
lyrics => 'USLT',
|
||||||
circle => 'TXXX=CIRCLE',
|
circle => 'TXXX=CIRCLE',
|
||||||
event => 'TXXX=EVENT',
|
|
||||||
discid => 'TXXX=DISCID',
|
|
||||||
originaltitle => 'TXXX=ORIGINALTITLE',
|
|
||||||
);
|
);
|
||||||
sub tagmap_catalogid {
|
sub tagmap_catalogid {
|
||||||
my $t = shift;
|
my $t = shift;
|
||||||
@ -141,17 +110,12 @@ sub tagmap_catalogid {
|
|||||||
|
|
||||||
my $opt_genre;
|
my $opt_genre;
|
||||||
my $opt_help;
|
my $opt_help;
|
||||||
my @opt_tagreplace;
|
|
||||||
my $opt_cbr = 0;
|
|
||||||
GetOptions(
|
GetOptions(
|
||||||
"genre|g=s" => \$opt_genre,
|
"genre|g=s" => \$opt_genre,
|
||||||
"no-genre|G" => \$opt_no_genre,
|
"no-genre|G" => \$opt_no_genre,
|
||||||
"replay-gain|r" => \$opt_rg,
|
|
||||||
"help|h" => \$opt_help,
|
"help|h" => \$opt_help,
|
||||||
"catid=s" => \$opt_catid,
|
"catid=s" => \$opt_catid,
|
||||||
"comment=s" => \$opt_comment,
|
"comment=s" => \$opt_comment,
|
||||||
"tagreplace|t=s" => \@opt_tagreplace,
|
|
||||||
"320|3" => \$opt_cbr,
|
|
||||||
) or die("Error in command line option");
|
) or die("Error in command line option");
|
||||||
|
|
||||||
if ($opt_help) {
|
if ($opt_help) {
|
||||||
@ -176,12 +140,9 @@ sub iterFlac {
|
|||||||
return if (!-f || !/\.flac$/);
|
return if (!-f || !/\.flac$/);
|
||||||
|
|
||||||
my @required_tags = ("artist", "title", "album", "tracknumber");
|
my @required_tags = ("artist", "title", "album", "tracknumber");
|
||||||
my $flacDir = substr($File::Find::name, length($IDIR));
|
|
||||||
my $flac = $_;
|
my $flac = $_;
|
||||||
my $flac_o = $flac;
|
|
||||||
shellsan(\$flac);
|
shellsan(\$flac);
|
||||||
my $dest = "$ODIR/" . $flacDir;
|
my $dest = "$ODIR/" . basename($flac);
|
||||||
#print("DEBUG: $dest\n");
|
|
||||||
$dest =~ s/\.flac$/\.mp3/;
|
$dest =~ s/\.flac$/\.mp3/;
|
||||||
my $tags = getFlacTags($flac);
|
my $tags = getFlacTags($flac);
|
||||||
|
|
||||||
@ -194,50 +155,24 @@ sub iterFlac {
|
|||||||
}
|
}
|
||||||
if (!$has_req_tags) {
|
if (!$has_req_tags) {
|
||||||
print("WARNING: File: '$flac' does not have all the required tags. Skipping\n");
|
print("WARNING: File: '$flac' does not have all the required tags. Skipping\n");
|
||||||
exit(1);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
argsToTags($tags, $flac_o);
|
argsToTags($tags);
|
||||||
my $tagopts = tagsToOpts($tags);
|
my $tagopts = tagsToOpts($tags);
|
||||||
|
|
||||||
#print("Debug: @$tagopts\n");
|
qx(flac -cd -- '$flac' | lame -V0 -S --vbr-new --add-id3v2 @$tagopts - '$dest');
|
||||||
shellsan(\$dest);
|
|
||||||
my $cmd;
|
|
||||||
if ($opt_cbr) {
|
|
||||||
$cmd = "flac -cd -- '$flac' | lame -S -b 320 -q 0 --add-id3v2 @$tagopts - '$dest'";
|
|
||||||
} else {
|
|
||||||
$cmd = "flac -cd -- '$flac' | lame -S -V0 --vbr-new -q 0 --add-id3v2 @$tagopts - '$dest'";
|
|
||||||
}
|
|
||||||
#print("Debug - CMD: [$cmd]\n");
|
|
||||||
qx($cmd);
|
|
||||||
if ($? != 0) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub argsToTags {
|
sub argsToTags {
|
||||||
my $argTags = shift;
|
my $argTags = shift;
|
||||||
my $fname = shift;
|
|
||||||
$fname =~ s!^.*/!!;
|
|
||||||
if (defined($opt_genre)) {
|
if (defined($opt_genre)) {
|
||||||
$argTags->{genre} = $opt_genre;
|
$argTags->{genre} = $opt_genre;
|
||||||
}
|
} elsif (defined($opt_comment) && $opt_comment ne "") {
|
||||||
if (defined($opt_comment) && $opt_comment ne "") {
|
|
||||||
$argTags->{comment} = $opt_comment;
|
$argTags->{comment} = $opt_comment;
|
||||||
}
|
} elsif (defined($opt_catid) && $opt_catid ne "") {
|
||||||
if (defined($opt_catid) && $opt_catid ne "") {
|
|
||||||
$argTags->{catalognumber} = $opt_catid;
|
$argTags->{catalognumber} = $opt_catid;
|
||||||
}
|
}
|
||||||
if (scalar @opt_tagreplace > 0) {
|
|
||||||
foreach my $trepl (@opt_tagreplace) {
|
|
||||||
$trepl =~ m!(.*?)/(.*?)=(.*)!;
|
|
||||||
my ($freg, $tag, $tagval) = ($1, $2, $3);
|
|
||||||
if ($fname =~ m!$freg!) {
|
|
||||||
$argTags->{lc($tag)} = $tagval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub tagsToOpts {
|
sub tagsToOpts {
|
||||||
@ -253,38 +188,14 @@ sub tagsToOpts {
|
|||||||
my $tagName = $idLookup{$currKey};
|
my $tagName = $idLookup{$currKey};
|
||||||
my $type = ref($tagName);
|
my $type = ref($tagName);
|
||||||
if ($type eq "" && defined($tagName)) {
|
if ($type eq "" && defined($tagName)) {
|
||||||
# If tag name is defined and tag contents exists
|
|
||||||
my $tagCont = $tags->{$currKey};
|
my $tagCont = $tags->{$currKey};
|
||||||
shellsan(\$tagCont);
|
shellsan(\$tagCont);
|
||||||
push(@tagopts, qq(--tv '$tagName=$tagCont'));
|
push(@tagopts, qq(--tv '$tagName=$tagCont'));
|
||||||
} elsif ($type eq "ARRAY") {
|
} elsif ($type eq "ARRAY") {
|
||||||
my $tagCont = $tagName->[1]->($tags);
|
my $tagCont = $tagName->[1]->($tags);
|
||||||
my $tagKey = $tagName->[0];
|
|
||||||
if (defined($tagCont)) {
|
if (defined($tagCont)) {
|
||||||
if (defined($tagKey)) {
|
shellsan(\$tagCont);
|
||||||
shellsan(\$tagCont);
|
push(@tagopts, qq(--tv '$tagName->[0]=$tagCont'));
|
||||||
push(@tagopts, qq(--tv '$tagName->[0]=$tagCont'));
|
|
||||||
} else {
|
|
||||||
if (ref($tagCont) eq 'ARRAY') {
|
|
||||||
# If we have an array of tags
|
|
||||||
foreach my $tC (@$tagCont) {
|
|
||||||
shellsan(\$tC);
|
|
||||||
push(@tagopts, qq(--tv '$tC'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
# If we have only one
|
|
||||||
shellsan(\$tagCont);
|
|
||||||
push(@tagopts, qq(--tv '$tagCont'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elsif ($type eq 'CODE') {
|
|
||||||
# If we have just a code reference
|
|
||||||
# do not assume, that this is a tag, rather a general cmd opt
|
|
||||||
my $opt = $tagName->($tags);
|
|
||||||
if (defined($opt)) {
|
|
||||||
shellsan(\$opt);
|
|
||||||
push(@tagopts, qq($opt));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,15 +209,8 @@ sub getFlacTags {
|
|||||||
|
|
||||||
my %tags;
|
my %tags;
|
||||||
my @tagtxt = qx(metaflac --list --block-type=VORBIS_COMMENT -- '$flac');
|
my @tagtxt = qx(metaflac --list --block-type=VORBIS_COMMENT -- '$flac');
|
||||||
if ($? != 0) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
foreach my $tagline (@tagtxt) {
|
foreach my $tagline (@tagtxt) {
|
||||||
if ($tagline =~ /comment\[\d+\]:\s(.*?)=(.*)/) {
|
if ($tagline =~ /comment\[\d+\]:\s(.*?)=(.*)/) {
|
||||||
if ($2 eq '') {
|
|
||||||
print("Empty tag: $1\n");
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
$tags{lc($1)} = $2;
|
$tags{lc($1)} = $2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -318,7 +222,7 @@ sub shellsan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub usage {
|
sub usage {
|
||||||
print("Usage: flac2mp3.pl [-h | --help] [-r] [-3] [-g | --genre NUM] <input_dir> <output_dir>\n");
|
print("Usage: flac2mp3.pl [-h | --help] [-g | --genre NUM] <input_dir> <output_dir>\n");
|
||||||
exit 1;
|
exit 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,12 +234,8 @@ Usage:
|
|||||||
-h, --help print this help text
|
-h, --help print this help text
|
||||||
-g, --genre NUM force this genre as a tag (lame --genre-list)
|
-g, --genre NUM force this genre as a tag (lame --genre-list)
|
||||||
-G, --no-genre ignore genre in flac file
|
-G, --no-genre ignore genre in flac file
|
||||||
-r, --replay-gain use replay gain values
|
|
||||||
--catid STRING the catalog id to set (or "")
|
--catid STRING the catalog id to set (or "")
|
||||||
--comment STRING the comment to set (or "")
|
--comment STRING the comment to set (or "")
|
||||||
-t --tagreplace STR Replace flac tags for a specific file only
|
|
||||||
Like -t '02*flac/TITLE=Some other title'
|
|
||||||
-3, --320 Convert into CBR 320 instead into the default V0
|
|
||||||
EOF
|
EOF
|
||||||
print($h);
|
print($h);
|
||||||
exit 0;
|
exit 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user