|
- #!/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;
-
- if (!-e $ODIR) {
- mkdir $ODIR;
- }
-
- 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);
-
- $flac =~ s!'!'\\''!g;
- 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
|