- #!/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"]+)|"((?:[^"]|(?<=(?<!\\)\\)")*)")/g){
- push(@lt, $1);
- $lt[$#lt] =~ s/\\([\\"])/$1/g;
- }
- if($lt[0] eq "PERFORMER" || $lt[0] eq "TITLE"){
- $pt->{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);
- }