mirror of
https://github.com/moex3/flac2mp3.pl
synced 2024-11-16 09:30:26 -05:00
Up.
This commit is contained in:
commit
dfb21dfc2b
15
README.md
Normal file
15
README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# flac2mp3.pl
|
||||||
|
Perl script to transcode flac into mp3, while keeping the tags. Because hundreds of these scripts aren't enough apparently.
|
||||||
|
|
||||||
|
Dependencies: `flac` `metaflac` `lame`
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
```bash
|
||||||
|
flac2mp3.pl ~/flacs ~/mp3
|
||||||
|
```
|
||||||
|
|
||||||
|
Tags can be overridden with options. Only the genre tag is supported rith now.
|
||||||
|
```bash
|
||||||
|
flac2mp3.pl --genre 145 ~/flacs ~/mp3
|
||||||
|
```
|
||||||
|
This would add the genre as 'Anime'. Run `lame --genre-list` for the whole list. Can be specified multiple ones, with comma separation (i think).
|
188
flac2mp3.pl
Executable file
188
flac2mp3.pl
Executable file
@ -0,0 +1,188 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Getopt::Long;
|
||||||
|
use File::Find;
|
||||||
|
use Data::Dumper;
|
||||||
|
use File::Basename;
|
||||||
|
|
||||||
|
# this is a godsent page
|
||||||
|
# https://wiki.hydrogenaud.io/index.php?title=Tag_Mapping
|
||||||
|
# a lot of this may not work
|
||||||
|
my %idLookup = (
|
||||||
|
album => 'TALB',
|
||||||
|
albumsort => 'TSOA',
|
||||||
|
discsubtitle => 'TSST',
|
||||||
|
grouping => 'TIT1',
|
||||||
|
title => 'TIT2',
|
||||||
|
titlesort => 'TSOT',
|
||||||
|
subtitle => 'TIT3',
|
||||||
|
subtitle => 'TIT3',
|
||||||
|
albumartist => 'TPE2',
|
||||||
|
albumartistsort => 'TSO2', # Maybe?
|
||||||
|
artist => 'TPE1',
|
||||||
|
artistsort => 'TSOP',
|
||||||
|
arranger => 'TIPL=arranger',
|
||||||
|
author => 'TEXT',
|
||||||
|
composer => 'TCOM',
|
||||||
|
conductor => 'TPE3',
|
||||||
|
engineer => 'TIPL=engineer',
|
||||||
|
djmixer => 'TIPL=DJ-mix',
|
||||||
|
mixer => 'TIPL=mix',
|
||||||
|
#performer => 'TMCL', # This produces some really weird tags
|
||||||
|
producer => 'TIPL=producer',
|
||||||
|
publisher => 'TPUB',
|
||||||
|
label => 'TPUB',
|
||||||
|
remixer => 'TPE4',
|
||||||
|
discnumber => ['TPOS', sub {
|
||||||
|
my $t = shift;
|
||||||
|
return "$t->{discnumber}" if !exists($t->{disctotal});
|
||||||
|
return "$t->{discnumber}/$t->{disctotal}";
|
||||||
|
}],
|
||||||
|
disctotal => undef,
|
||||||
|
tracknumber => ['TRCK', sub {
|
||||||
|
my $t = shift;
|
||||||
|
return "$t->{tracknumber}" if !exists($t->{tracktotal});
|
||||||
|
return "$t->{tracknumber}/$t->{tracktotal}";
|
||||||
|
}],
|
||||||
|
tracktotal => undef,
|
||||||
|
date => 'TDRC', # This is for id3v2.4
|
||||||
|
originaldate => 'TDOR', # Also for 2.4 only
|
||||||
|
isrc => 'TSRC',
|
||||||
|
barcode => 'TXXX=BARCODE',
|
||||||
|
catalognumber => 'TXXX=CATALOGNUMBER',
|
||||||
|
catalog => 'TXXX=CATALOGNUMBER',
|
||||||
|
catalogid => 'TXXX=CATALOGNUMBER',
|
||||||
|
'encoded-by' => 'TENC',
|
||||||
|
encoder => 'TSSE',
|
||||||
|
encoding => 'TSSE',
|
||||||
|
'encoder settings' => 'TSSE',
|
||||||
|
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 {
|
||||||
|
return 24;
|
||||||
|
}],
|
||||||
|
#mood => ['TMOO', sub {
|
||||||
|
#}],
|
||||||
|
bpm => 'TBPM',
|
||||||
|
comment => 'COMM',
|
||||||
|
copyright => 'TCOP',
|
||||||
|
language => 'TLAN',
|
||||||
|
script => 'TXXX=SCRIPT',
|
||||||
|
lyrics => 'USLT',
|
||||||
|
);
|
||||||
|
|
||||||
|
my $opt_genre;
|
||||||
|
my $opt_help;
|
||||||
|
GetOptions(
|
||||||
|
"genre=s" => \$opt_genre,
|
||||||
|
"help" => \$opt_help
|
||||||
|
) or die("Error in command line option");
|
||||||
|
|
||||||
|
if ($opt_help) {
|
||||||
|
help();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scalar(@ARGV) != 2) {
|
||||||
|
print("Bad arguments\n");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($IDIR, $ODIR) = @ARGV;
|
||||||
|
|
||||||
|
find({ wanted => \&iterFlac, no_chdir => 1 }, $IDIR);
|
||||||
|
|
||||||
|
sub iterFlac {
|
||||||
|
# Return if file is not a file, or if it's not a flac
|
||||||
|
return if (!-f || !/\.flac$/);
|
||||||
|
|
||||||
|
my @required_tags = ("artist", "title", "album", "tracknumber");
|
||||||
|
my $flac = $_;
|
||||||
|
my $dest = "$ODIR/" . basename($flac);
|
||||||
|
$dest =~ s/\.flac$/\.mp3/;
|
||||||
|
my $tags = getFlacTags($flac);
|
||||||
|
|
||||||
|
my $has_req_tags = 1;
|
||||||
|
foreach (@required_tags) {
|
||||||
|
if (!exists($tags->{lc($_)})) {
|
||||||
|
$has_req_tags = 0;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$has_req_tags) {
|
||||||
|
print("WARNING: File: '$flac' does not have all the required tags. Skipping\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
argsToTags($tags);
|
||||||
|
my $tagopts = tagsToOpts($tags);
|
||||||
|
|
||||||
|
qx(flac -cd "$flac" | lame -V0 -S --vbr-new --add-id3v2 @$tagopts - "$dest");
|
||||||
|
}
|
||||||
|
|
||||||
|
sub argsToTags {
|
||||||
|
my $argTags = shift;
|
||||||
|
if (defined($opt_genre)) {
|
||||||
|
$argTags->{genre} = $opt_genre;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub tagsToOpts {
|
||||||
|
my $tags = shift;
|
||||||
|
my @tagopts;
|
||||||
|
|
||||||
|
# TODO escape ' and =?
|
||||||
|
foreach my $currKey (keys (%$tags)) {
|
||||||
|
if (!exists($idLookup{$currKey})) {
|
||||||
|
print("Tag: '$currKey' doesn't have a mapping, skipping\n");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
my $tagName = $idLookup{$currKey};
|
||||||
|
my $type = ref($tagName);
|
||||||
|
if ($type eq "" && defined($tagName)) {
|
||||||
|
push(@tagopts, qq(--tv '$tagName=$tags->{$currKey}'));
|
||||||
|
} elsif ($type eq "ARRAY") {
|
||||||
|
my $tagCont = $tagName->[1]->($tags);
|
||||||
|
push(@tagopts, qq(--tv '$tagName->[0]=$tagCont'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#print(Dumper(\@tagopts));
|
||||||
|
return \@tagopts;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getFlacTags {
|
||||||
|
my $flac = shift;
|
||||||
|
|
||||||
|
my %tags;
|
||||||
|
my @tagtxt = qx(metaflac --list --block-type=VORBIS_COMMENT -- "$flac");
|
||||||
|
foreach my $tagline (@tagtxt) {
|
||||||
|
if ($tagline =~ /comment\[\d+\]:\s(.*?)=(.*)/) {
|
||||||
|
$tags{lc($1)} = $2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return \%tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub usage {
|
||||||
|
print("Usage: flac2mp3.pl [-h | --help] [-g | --genre NUM] <input_dir> <output_dir>\n");
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub help {
|
||||||
|
my $h = <<EOF;
|
||||||
|
Usage:
|
||||||
|
flac2mp3.pl [options] <input_dir> <output_dir>
|
||||||
|
|
||||||
|
-h, --help print this help text
|
||||||
|
-g, --genre NUM force this genre as a tag (lame --genre-list)
|
||||||
|
EOF
|
||||||
|
print($h);
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: ts=4 sw=4 et sta
|
Loading…
Reference in New Issue
Block a user