|
|
@ -2,9 +2,10 @@ package Subtitle::SRT; |
|
|
|
|
|
|
|
|
|
|
|
use strict; |
|
|
|
use strict; |
|
|
|
use warnings; |
|
|
|
use warnings; |
|
|
|
use feature qw(switch); |
|
|
|
|
|
|
|
use utf8; |
|
|
|
use utf8; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use Subtitle::Utils qw(:string :timing); |
|
|
|
|
|
|
|
|
|
|
|
use base 'Subtitle::BASE'; |
|
|
|
use base 'Subtitle::BASE'; |
|
|
|
|
|
|
|
|
|
|
|
sub new { |
|
|
|
sub new { |
|
|
@ -15,7 +16,7 @@ sub new { |
|
|
|
%args, |
|
|
|
%args, |
|
|
|
events => [], |
|
|
|
events => [], |
|
|
|
log => [], |
|
|
|
log => [], |
|
|
|
timing_fmt => "%02d:%02d:%02d,%s", |
|
|
|
timing_fmt => "%02d:%02d:%02d,%03d", |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
return bless($self, $class); |
|
|
|
return bless($self, $class); |
|
|
@ -28,13 +29,14 @@ sub parse { |
|
|
|
my $linenum = 0; |
|
|
|
my $linenum = 0; |
|
|
|
my $event; |
|
|
|
my $event; |
|
|
|
|
|
|
|
|
|
|
|
foreach my $line (@$lines) { |
|
|
|
foreach my $line (@{ $lines }) { |
|
|
|
$linenum++; |
|
|
|
$linenum++; |
|
|
|
$line = $self->chomp($line); |
|
|
|
chomp_all($line); |
|
|
|
# expected: event id |
|
|
|
# expected: event id |
|
|
|
if ($line and not $event) { |
|
|
|
if ($line and not $event) { |
|
|
|
$event = $self->new_event; |
|
|
|
$event = $self->new_event; |
|
|
|
$event->{id} = $self->trim($line); |
|
|
|
trim($line); |
|
|
|
|
|
|
|
$event->{id} = $line; |
|
|
|
$self->log(debug => "New event with id: $event->{id}"); |
|
|
|
$self->log(debug => "New event with id: $event->{id}"); |
|
|
|
next; |
|
|
|
next; |
|
|
|
} |
|
|
|
} |
|
|
@ -47,16 +49,18 @@ sub parse { |
|
|
|
$self->log(warn => "Expected timing but found `$line` at $linenum, skipped"); |
|
|
|
$self->log(warn => "Expected timing but found `$line` at $linenum, skipped"); |
|
|
|
next; |
|
|
|
next; |
|
|
|
} |
|
|
|
} |
|
|
|
unless (defined ($timing->[0] = $self->parse_timing($start))) { |
|
|
|
$timing->[0] = parse_timing($start); |
|
|
|
|
|
|
|
unless ($timing->[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; |
|
|
|
} |
|
|
|
} |
|
|
|
unless (defined ($timing->[1] = $self->parse_timing($end))) { |
|
|
|
$timing->[1] = parse_timing($end); |
|
|
|
|
|
|
|
unless ($timing->[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->{timing} = $timing; |
|
|
|
$rest = $self->trim($rest); |
|
|
|
trim($rest); |
|
|
|
next unless $rest; |
|
|
|
next unless $rest; |
|
|
|
# extension: timing |
|
|
|
# extension: timing |
|
|
|
# example: X1:050 X2:669 Y1:234 Y2:436 |
|
|
|
# example: X1:050 X2:669 Y1:234 Y2:436 |
|
|
@ -81,8 +85,9 @@ sub parse { |
|
|
|
$rest = $1; |
|
|
|
$rest = $1; |
|
|
|
foreach my $token (split(/\s*,\s*/, $rest)) { |
|
|
|
foreach my $token (split(/\s*,\s*/, $rest)) { |
|
|
|
next unless $token =~ m/^(\S+):\s*(.+)/o; |
|
|
|
next unless $token =~ m/^(\S+):\s*(.+)/o; |
|
|
|
|
|
|
|
trim($2); |
|
|
|
$event->{style} //= {}; |
|
|
|
$event->{style} //= {}; |
|
|
|
$event->{style}->{lc($1)} = $self->trim($2); |
|
|
|
$event->{style}->{lc($1)} = $2; |
|
|
|
} |
|
|
|
} |
|
|
|
next; |
|
|
|
next; |
|
|
|
} |
|
|
|
} |
|
|
@ -98,15 +103,14 @@ sub parse { |
|
|
|
} |
|
|
|
} |
|
|
|
# expected: event text |
|
|
|
# expected: event text |
|
|
|
if ($line and $event and $event->{timing}) { |
|
|
|
if ($line and $event and $event->{timing}) { |
|
|
|
|
|
|
|
trim($line); |
|
|
|
$self->log(debug => "Text line at $linenum -> append"); |
|
|
|
$self->log(debug => "Text line at $linenum -> append"); |
|
|
|
if ($event->{text}) { |
|
|
|
$event->{text} //= ''; |
|
|
|
$event->{text} .= $self->{eol} . $self->trim($line); |
|
|
|
$event->{text} .= $self->{eol} if $event->{text}; |
|
|
|
} else { |
|
|
|
$event->{text} .= $line; |
|
|
|
$event->{text} = $self->trim($line); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
next; |
|
|
|
next; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} # foreach @lines |
|
|
|
# finalize last event |
|
|
|
# finalize last event |
|
|
|
if ($event and $event->{timing} and $event->{text}) { |
|
|
|
if ($event and $event->{timing} and $event->{text}) { |
|
|
|
push @{ $self->{events} }, $event; |
|
|
|
push @{ $self->{events} }, $event; |
|
|
@ -117,13 +121,16 @@ sub parse { |
|
|
|
|
|
|
|
|
|
|
|
sub build { |
|
|
|
sub build { |
|
|
|
my ($self) = @_; |
|
|
|
my ($self) = @_; |
|
|
|
my $out = ""; |
|
|
|
my ($hrs, $min, $sec, $msec, $out); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$out = ''; |
|
|
|
foreach my $e (@{ $self->{events} }) { |
|
|
|
foreach my $e (@{ $self->{events} }) { |
|
|
|
$out .= "$e->{id}\n"; |
|
|
|
$out .= $e->{id} . "\n"; |
|
|
|
$out .= sprintf "%s --> %s\n", |
|
|
|
my $start = sprintf $self->{timing_fmt}, |
|
|
|
$self->build_timing($e->{timing}->[0], 3, ','), |
|
|
|
make_timing($e->{timing}->[0]); |
|
|
|
$self->build_timing($e->{timing}->[1], 3, ','); |
|
|
|
my $end = sprintf $self->{timing_fmt}, |
|
|
|
|
|
|
|
make_timing($e->{timing}->[1]); |
|
|
|
|
|
|
|
$out .= sprintf "%s --> %s\n", $start, $end; |
|
|
|
$out .= "$e->{text}\n"; |
|
|
|
$out .= "$e->{text}\n"; |
|
|
|
$out .= "\n"; |
|
|
|
$out .= "\n"; |
|
|
|
} |
|
|
|
} |
|
|
|