ogg批次轉mp3

看這裏

#!/usr/bin/perl -w
# Filename:	ogg2mp3
# Author:	David Ljung Madison <DaveSource.com>
# See License:	http://MarginalHacks.com/License
# Description:	Converts ogg to mp3, with artist/title/info
# Ideas from:  Joseph E. O'Doherty <odoherty.net>
# id3v2 from:  Javier Salazar Loyola <jsalazar cern ch>

use strict;
use File::Spec;

##################################################
# Setup the variables
##################################################
my $PROGNAME = $0;
$PROGNAME =~ s|.*/||;

my $TMPFILE = File::Spec->catfile( File::Spec->tmpdir(), "$PROGNAME.$$.wav" );

#########################
# Ogg decoder
#########################
# Different versions of ogg123 handle files differently!  Argh!
#my $OGGDEC = "ogg123 -d wav -o file:$TMPFILE";
#my $OGGDEC = "ogg123 -d wav -f $TMPFILE";
# Just use oggdec instead.
# Add -Q for quiet..
my $OGGDEC = "oggdec -o $TMPFILE";

#########################
# MP3 encoder
# Choose your favorite..
#########################
my $MP3ENC = "lame";
#my $MP3ENC = "notlame";

my $OGGINFO = "ogginfo";
my $ID3TOOL = "id3tool";
my $ID3V2   = "id3v2";

##################################################
# Usage
##################################################
sub usage {
  foreach my $msg (@_) { print STDERR "ERROR:  $msg\n"; }
print <<USAGE;

Usage:\t$PROGNAME [-d] [-o <dir>] [<playlist.m3u> | <ogg> ..]
  Converts ogg to mp3
  -d                  Set debug mode
  -o <dir>            Specify output directory
  -id3v2              Use id3v2 instead of id3tool for tagging
  -keepdir            Keep directory structure inside specified -o directory
  -f                  Force rewriting of mp3 if it already exists
  --enc_opts .. --    Options for encoding tool
  --dec_opts .. --    Options for decoding tool

  Example:  $PROGNAME --enc_opts -b 64 -- *.ogg

USAGE
  exit -1;
}

sub get_dashdash {
	my @dash;
	while ($#ARGV>=0) {
		my $arg=shift(@ARGV);
		last if $arg eq "--";
		push(@dash,$arg);
	}
	@dash;
}

sub contents {
	my ($f) = @_;
	open(F,"<$f") || usage("Couldn't read playlist [$f]");
	my @f = <F>;
	close F;
	chomp @f;
	@f;
}

sub parse_args {
	my $opt = {};
	my $outdir;
	my @oggs;
	while (my $arg=shift(@ARGV)) {
		if ($arg =~ /^-h$/) { usage(); }
		if ($arg =~ /^-d$/) { $MAIN::DEBUG=1; next; }
		if ($arg =~ /^-o$/) { $opt->{out}=shift @ARGV; next; }
		if ($arg =~ /^-id3v2$/) { $opt->{id3v2}=1; next; }
		if ($arg =~ /^-keepdir$/) { $opt->{keepdir}=1; next; }
		if ($arg =~ /^-f$/) { $opt->{force}=1; next; }
		if ($arg =~ /^--enc_opts$/) { push(@{$opt->{enc_opts}}, get_dashdash()); next; }
		if ($arg =~ /^--dec_opts$/) { push(@{$opt->{dec_opts}}, get_dashdash()); next; }
		if ($arg =~ /^-/) { usage("Unknown option: $arg"); }
		push(@oggs, ($arg =~ /\.m3u$/) ? contents($arg) : $arg);
	}
	usage("No oggs specified") unless @oggs;
	
	($opt,@oggs);
}

sub debug {
	return unless $MAIN::DEBUG;
	foreach my $msg (@_) { print STDERR "[$PROGNAME] $msg\n"; }
}

##################################################
# Genre code
##################################################
my @GENRES;
sub get_genres() {
	return if @GENRES;
	open(G,"$ID3TOOL -l|") || die("[$PROGNAME] Can't get genre info: [$ID3TOOL -l]\n");
	while (<G>) {
		push(@GENRES,$1) if (/^(\S.*\S)\s+\|/);
	}
	close G;
}

sub get_genre {
	my ($genre) = @_;
	return undef unless $genre;
	get_genres;
	my @g = grep(/^$genre$/i, @GENRES);
	return $g[0] if @g;
	@g = grep(/$genre/i, @GENRES);
	print STDERR "[$PROGNAME] Multiple genre matches [$genre -> @g]\n" if $#g>0;
	return $g[0] if @g;
	# No match
	print STDERR "[$PROGNAME] Unknown genre [$genre]\n";
	return undef;
}

##################################################
# Main code
##################################################
sub ogginfo {
	my ($ogg) = @_;
	
	# Get ogg tags
	open(TAGS,"$OGGINFO \Q$ogg\E |") || die("[$PROGNAME] Couldn't run ogginfo [$ogg]\n");
	my %i;
	while(<TAGS>) {
		chomp;
		next if /^\s*$/;

## The old way:
#		die("[$PROGNAME] Bad ogginfo: [$_]") unless /^\s*(\S+)=(.*)$/;
#		$i{$1} .= $2;

## Old ogginfo:
## "key=value"
##
## New ogginfo:
## "Some comment stuff..."
## "	key=value"
##
## I suppose I could parse the entire output to see if it's new or
## old, but it looks like the comments never have '=' in them, and who
## cares if it does anyways?  So, we'll just use a loose regexp:
		if (/^\s*(\S+)=(.*)$/) {
			my ($tag,$val) = (lc($1),$2);
			$i{$tag} .= $val
		}
	}
	close(TAGS);
	\%i;
}

sub dir {
	my ($path) = @_;
	return undef unless $path =~ m|/|;
	$path =~ s|/+$||;
	$path =~ s|/[^/]+$||;
	$path;
}

sub mkdirOf {
	my ($path) = @_;
	return if !defined $path || -d $path;
	mkdirOf(dir($path));
	mkdir($path)
}

sub set_mp3info {
	my ($opt,$mp3,$info) = @_;

	my $tool = $opt->{id3v2} ? $ID3V2 : $ID3TOOL;

	# Flags that are different
	my $trackFlag = $opt->{id3v2} ? 'T' : 'c';
	my $albumFlag = $opt->{id3v2} ? 'A' : 'a';
	my $artistFlag = $opt->{id3v2} ? 'a' : 'r';
	my $commentFlag = $opt->{id3v2} ? 'c' : 'n';
	my $genreFlag = $opt->{id3v2} ? 'g' : 'G';
	my $legitDate = $opt->{id3v2} ? '^[\d+-\/]$' : '^\d+$';

	my $set;
	# Newer id3tool supports setting track
	#$set .= " -n \QTrack $info->{tracknumber}\E" if $info->{tracknumber} && !$info->{comment};
	$set .= " -$trackFlag \Q$info->{tracknumber}\E" if $info->{tracknumber};
	$set .= " -t \Q$info->{title}\E" if $info->{title};
	$set .= " -$albumFlag \Q$info->{album}\E" if $info->{album};
	$set .= " -$artistFlag \Q$info->{artist}\E" if $info->{artist};
	$set .= " -$commentFlag \Q$info->{comment}\E" if $info->{comment};
	my $genre = $opt->{id3v2} ? $info->{genre} : get_genre($info->{genre});
	$set .= " -$genreFlag \Q$genre\E" if $genre;
	$set .= " -y \Q$info->{date}\E" if $info->{date} && $info->{date} =~ /$legitDate/;
	return print STDERR "[$PROGNAME] No tag info for [$mp3]\n" unless $set;
	system("$tool $set \Q$mp3\E");
	print STDERR "[$PROGNAME] Errors from:\n  $tool $set $mp3\n  $!\n" if $?;
}

sub ogg2mp3 {
	my ($opt,$ogg) = @_;
	my $mp3 = $ogg;
	$mp3 =~ s/(\.ogg)?$/.mp3/i;

	# Handle outdir if specified
	if ($opt->{out}) {
		$mp3 =~ s|.*/||g unless $opt->{keepdir};
		$mp3 = "$opt->{out}/$mp3";
	}

	return print STDERR "[$PROGNAME] Skipping mp3 (already exists) [$mp3]\n"
		if !$opt->{force} && -f $mp3;

	# Make sure the directory exists
	mkdirOf(dir($mp3));

	my $dec_opts = $opt->{dec_opts} ? join(' ',@{$opt->{dec_opts}}) : "";
	my $enc_opts = $opt->{enc_opts} ? join(' ',@{$opt->{enc_opts}}) : "";

	print "$ogg -> $mp3\n";

	# Decode
#	system("$OGGDEC \Q$ogg\E | $MP3ENC - \Q$mp3\E");
#	print STDERR "[$PROGNAME] Errors from:\n  $OGGDEC \Q$ogg\E | $MP3ENC - \Q$mp3\E\n  $!\n"
#		if $?;
	system("$OGGDEC $dec_opts \Q$ogg\E");
	print STDERR "[$PROGNAME] Errors from:\n  $OGGDEC \Q$ogg\E\n  $!\n" if $?;

	# Encode
	system("$MP3ENC $enc_opts $TMPFILE \Q$mp3\E");
	print STDERR "[$PROGNAME] Errors from:\n  $MP3ENC $TMPFILE \Q$mp3\E\n  $!\n" if $?;
	unlink $TMPFILE;


	my $info = ogginfo($ogg);
	set_mp3info($opt,$mp3,$info);
}

sub main {
	my ($opt,@oggs) = parse_args();

	map(ogg2mp3($opt,$_), @oggs);
}
main();
分類: 多媒體。這篇內容的永久連結

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *