|
|
@ -4,6 +4,7 @@ use strict; |
|
|
|
use warnings; |
|
|
|
use warnings; |
|
|
|
use utf8; |
|
|
|
use utf8; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use Subtitle::Event; |
|
|
|
use Subtitle::Utils qw(:string :timing); |
|
|
|
use Subtitle::Utils qw(:string :timing); |
|
|
|
|
|
|
|
|
|
|
|
use base 'Subtitle::Format'; |
|
|
|
use base 'Subtitle::Format'; |
|
|
@ -11,9 +12,8 @@ use base 'Subtitle::Format'; |
|
|
|
sub new { |
|
|
|
sub new { |
|
|
|
my ($class, %args) = @_; |
|
|
|
my ($class, %args) = @_; |
|
|
|
my $self = { |
|
|
|
my $self = { |
|
|
|
debug => 0, |
|
|
|
debug => $args{debug} || 0, |
|
|
|
eol => "\n", |
|
|
|
eol => $args{eol} || "\n", |
|
|
|
%args, |
|
|
|
|
|
|
|
events => [], |
|
|
|
events => [], |
|
|
|
log => [], |
|
|
|
log => [], |
|
|
|
timing_fmt => "%02d:%02d:%02d,%03d", |
|
|
|
timing_fmt => "%02d:%02d:%02d,%03d", |
|
|
@ -22,7 +22,7 @@ sub new { |
|
|
|
return bless($self, $class); |
|
|
|
return bless($self, $class); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
sub new_event { return +{ id => undef, timing => undef, text => undef }; } |
|
|
|
sub new_event { return Subtitle::Event->new; } |
|
|
|
|
|
|
|
|
|
|
|
sub parse { |
|
|
|
sub parse { |
|
|
|
my ($self, $lines) = @_; |
|
|
|
my ($self, $lines) = @_; |
|
|
@ -41,25 +41,26 @@ sub parse { |
|
|
|
next; |
|
|
|
next; |
|
|
|
} |
|
|
|
} |
|
|
|
# expected: timing |
|
|
|
# expected: timing |
|
|
|
if ($line and $event and not $event->{timing}) { |
|
|
|
if ($line and $event and not ($event->t_start or $event->t_end)) { |
|
|
|
$self->log(debug => "Expecting timing line at $linenum"); |
|
|
|
$self->log(debug => "Expecting timing line at $linenum"); |
|
|
|
my $timing = []; |
|
|
|
my @t; |
|
|
|
my ($start, $end, $rest) = ($line =~ m/(\S+)\s*-->\s*(\S+)(.*)/o); |
|
|
|
my ($start, $end, $rest) = ($line =~ m/(\S+)\s*-->\s*(\S+)(.*)/o); |
|
|
|
unless ($start and $end) { |
|
|
|
unless ($start and $end) { |
|
|
|
$self->log(warn => "Expected timing but found `$line` at $linenum, skipped"); |
|
|
|
$self->log(warn => "Expected timing but found `$line` at $linenum, skipped"); |
|
|
|
next; |
|
|
|
next; |
|
|
|
} |
|
|
|
} |
|
|
|
$timing->[0] = parse_timing($start); |
|
|
|
$t[0] = parse_timing($start); |
|
|
|
unless ($timing->[0] >= 0) { |
|
|
|
unless ($t[0] >= 0) { |
|
|
|
$self->log(warn => "Can't parse timing at line $linenum: $start"); |
|
|
|
$self->log(warn => "Can't parse timing at line $linenum: $start"); |
|
|
|
next; |
|
|
|
next; |
|
|
|
} |
|
|
|
} |
|
|
|
$timing->[1] = parse_timing($end); |
|
|
|
$t[1] = parse_timing($end); |
|
|
|
unless ($timing->[1] >= 0) { |
|
|
|
unless ($t[1] >= 0) { |
|
|
|
$self->log(warn => "Can't parse timing at line $linenum: $end"); |
|
|
|
$self->log(warn => "Can't parse timing at line $linenum: $end"); |
|
|
|
next; |
|
|
|
next; |
|
|
|
} |
|
|
|
} |
|
|
|
$event->{timing} = $timing; |
|
|
|
$event->t_start($t[0]); |
|
|
|
|
|
|
|
$event->t_end ($t[1]); |
|
|
|
trim($rest); |
|
|
|
trim($rest); |
|
|
|
next unless $rest; |
|
|
|
next unless $rest; |
|
|
|
# extension: timing |
|
|
|
# extension: timing |
|
|
@ -102,17 +103,18 @@ sub parse { |
|
|
|
next; |
|
|
|
next; |
|
|
|
} |
|
|
|
} |
|
|
|
# expected: event text |
|
|
|
# expected: event text |
|
|
|
if ($line and $event and $event->{timing}) { |
|
|
|
if ($line and $event and ($event->t_start or $event->t_end)) { |
|
|
|
trim($line); |
|
|
|
trim($line); |
|
|
|
$self->log(debug => "Text line at $linenum -> append"); |
|
|
|
$self->log(debug => "Text line at $linenum -> append"); |
|
|
|
$event->{text} //= ''; |
|
|
|
my $text = $event->text; |
|
|
|
$event->{text} .= $self->{eol} if $event->{text}; |
|
|
|
$text .= $self->{eol} if $text; |
|
|
|
$event->{text} .= $line; |
|
|
|
$text .= $line; |
|
|
|
|
|
|
|
$event->text($text); |
|
|
|
next; |
|
|
|
next; |
|
|
|
} |
|
|
|
} |
|
|
|
} # foreach @lines |
|
|
|
} # foreach @lines |
|
|
|
# finalize last event |
|
|
|
# finalize last event |
|
|
|
if ($event and $event->{timing} and $event->{text}) { |
|
|
|
if ($event and $event->text and ($event->t_start or $event->t_end)) { |
|
|
|
push @{ $self->{events} }, $event; |
|
|
|
push @{ $self->{events} }, $event; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -125,12 +127,10 @@ sub build { |
|
|
|
|
|
|
|
|
|
|
|
foreach my $e (@{ $self->{events} }) { |
|
|
|
foreach my $e (@{ $self->{events} }) { |
|
|
|
push @lines, $e->{id}; |
|
|
|
push @lines, $e->{id}; |
|
|
|
my $start = sprintf $self->{timing_fmt}, |
|
|
|
my $start = sprintf $self->{timing_fmt}, make_timing($e->t_start); |
|
|
|
make_timing($e->{timing}->[0]); |
|
|
|
my $end = sprintf $self->{timing_fmt}, make_timing($e->t_end); |
|
|
|
my $end = sprintf $self->{timing_fmt}, |
|
|
|
push @lines, sprintf "%s --> %s", $start, $end; |
|
|
|
make_timing($e->{timing}->[1]); |
|
|
|
push @lines, $e->text; |
|
|
|
push @lines, sprintf("%s --> %s", $start, $end); |
|
|
|
|
|
|
|
push @lines, $e->{text}; |
|
|
|
|
|
|
|
push @lines, ""; |
|
|
|
push @lines, ""; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|