#!/usr/bin/perl use warnings; use strict; use utf8; use Encode; use open ":locale"; sub usage{ print << "EOT" usage: $0 CUEFILE.cue [:ENCODING] [WAV-OVERRIDE] [+FORMAT] [- FFMPEG-OPTIONS...] Encoding: This is PerlIO layer selector. You can use :encoding(CHARCODE) to set cue file charcode. Wav override: Normally, this program reads audio from file which specified by cue. You can override this filename. Format: Output filename format. If not spicified, use "+%n-%02t.ogg" %[0-9]*n: Track number %t : Track name %p : Track performer %T : Album name %P : Album performer FFmpeg options: Pass these options to FFmpeg as output file options. If not specified, use "-c:a libopus -b:a 64k -vn -sn" EOT ; exit(shift|0); } my $cuename; my $cueenc = ""; my $wavor; my $fnpat; my @encops; for(@ARGV){ if(/^(?:-h|--help|-help|-\?)$/){ usage(0); }elsif(/^-/ .. 0){ push(@encops, $_); }elsif(!defined($fnpat) && /^\+/){ $fnpat = substr($_, 1); }elsif(!length($cueenc) && /^:/){ $cueenc = $_; }elsif(!defined($cuename)){ $cuename = $_; }elsif(!defined($wavor)){ $wavor = $_; }else{ usage(1); } } if(!defined($fnpat)){ $fnpat = "%n-%02t.ogg"; } if(!@encops){ @encops = qw(-c:a libopus -b:a 64k -vn -sn); } shift(@encops) if(@encops && $encops[0] eq "-"); if(!defined($cuename)){ usage(1); } my @tracks; my $disc = {}; my $pt = $disc; my $cue; open($cue, "<$cueenc", $cuename) || die "cue open error"; while(<$cue>){ my @lt; while(/(?|([^\s"]+)|"((?:[^"]|(?<=(?{lc($lt[0])} = $lt[1]; }elsif($lt[0] eq "FILE"){ $wavor = $lt[1] if(!defined($wavor)); }elsif($lt[0] eq "INDEX"){ if($lt[2] !~ /^([0-9]{2}):([0-9]{2}):([0-9]{2})$/){ die "index error"; } my $s = $1 * 60 + $2 + $3 / 75; if($lt[1] == 0){ $pt->{prgap} = $s; }elsif($lt[1] == 1){ $pt->{start} = $s; $pt->{prgap} = $s if(!defined($pt->{prgap})); } }elsif($lt[0] eq "TRACK"){ if($tracks[$lt[1]]){ die "track has same number"; } $pt = {num => +$lt[1]}; $tracks[$lt[1] - 1] = $pt; } } if(!defined($wavor)){ die "give audio file"; } for(0 .. $#tracks){ my $track = $tracks[$_]; if(!$track){ next; } my @lo; @lo = ("-t", $tracks[$_+1]{prgap} - $track->{start}) if($tracks[$_+1]); my %ma = ( track => $track->{num}, title => $track->{title}, artist => $track->{performer}, album => $disc->{title}, album_artist => $disc->{performer} ); my @metaops; while(my ($k, $v) = each(%ma)){ push(@metaops, "-metadata", "$k=$v") if(defined($v)); } my %fa = ( n => $track->{num}, t => $track->{title}, p => $track->{performer}, T => $disc->{title}, P => $disc->{performer} ); my $fh = sub{ my $l = shift || 0; my $n = shift; my $p = ($l =~ /^0/) ? "0" : " "; my $r = defined($fa{$n}) ? $fa{$n} : ""; my $a = $l - length($r); $a = 0 if($a < 0); return ($p x $a) . $r; }; my $fname = $fnpat; $fname =~ s/%([0-9]*)([ntpTP])/$fh->($1, $2)/ge; system("ffmpeg", "-ss", $track->{start}, "-i", $wavor, @metaops, @encops, @lo, $fname); }