package Subtitle::Format::MSub; use strict; use warnings; use utf8; use Subtitle::Event; use Subtitle::Utils qw(:string round); use base 'Subtitle::Format'; sub new { my ($class, %args) = @_; my $self = { debug => $args{debug} || 0, fps => $args{fps} || 25.0, eol => $args{eol} || "\n", events => [], log => [], }; return bless($self, $class); } sub new_event { return Subtitle::Event->new; } sub parse { my ($self, $lines) = @_; my $linenum = 0; my $event; foreach my $line (@{ $lines }) { $linenum++; chomp_all($line); trim($line); next unless $line; my ($start, $end, $rest) = ($line =~ m/{(\d+)}\s*{(\d+)}\s*(.+)/o); # expected: garbage unless ($start and $end and $rest) { $self->log(warn => "Unrecognized line at $linenum: $line"); next; } # expected: valid line # special case - '{1}{1}XX.YY' line sets fps if ($start == 1 and $end == 1) { my ($fps) = ($rest =~ m/(\d+(?:\.\d+))/o); unless ($fps) { $self->log(error => "Expected fps at line $linenum, but found: $rest"); next; } $self->log(debug => "Set fps to $fps and line $linenum"); $self->{fps} = $fps; next; } trim($rest); $rest =~ s/\|/$self->{eol}/og; my $event = $self->new_event; $event->t_start($start / $self->{fps}); $event->t_end ($end / $self->{fps}); $event->text($rest); push @{ $self->{events} }, $event; undef $event; } return scalar @{ $self->{events} }; } sub build { my ($self) = @_; my @lines; push @lines, sprintf "{1}{1}%.3f", $self->{fps}; foreach my $e (@{ $self->{events} }) { my $show = round($e->t_start * $self->{fps}, 0); my $hide = round($e->t_end * $self->{fps}, 0); my $text = ($e->{text} =~ s{$self->{eol}}{|}gr); push @lines, sprintf "{%d}{%d}%s", $show, $hide, $text; } push @lines, ""; return join($self->{eol} => @lines); } 1; =pod =head1 NAME Subtitle::MSub -- micsrosub subtitle format =head1 METHODS =head2 C my $msub = Subtitle::MSub->new(%opts); Creates new object, takes list of options as argument. Recognized keys are: * debug -- write debug messages to log (default: 0) * eol -- replace "|" symbol within subtitle text with this chars (default: "\n") * fps -- sets FPS for subtitle (default: 25.0, try detect from file) * convert_timing -- convert frame numbers to seconds (default: 1) =head2 C my $events_count = $msub->parse(\@lines); Parse subtitle from array of lines. Returns parsed events count on success, -1 on error =head2 C my $text = $msub->build(); Builds parsed subtitle to string. =cut