Sync subtitles: Difference between revisions

Content added Content deleted
(added Raku programming solutions)
(→‎Less brutal: use grammar actions and add encapsulations)
 
Line 1,146: Line 1,146:


===Less brutal===
===Less brutal===
<syntaxhighlight lang="raku" line># 20240621 Raku programming solution
<syntaxhighlight lang="raku" line># 20240622 Raku programming solution


grammar SRT { # loc.gov/preservation/digital/formats/fdd/fdd000569.shtml
grammar SRT { # loc.gov/preservation/digital/formats/fdd/fdd000569.shtml
Line 1,158: Line 1,158:
}
}


class SRT::Actions { has @.subtitles;
sub parse-srt($srt-content) {
my $parsed = SRT.parse($srt-content);
return $parsed
?? $parsed<subtitle>.map(-> $sub { {
index => $sub<index>.Str,
start => $sub<timecode><timestamp>[0].Str,
end => $sub<timecode><timestamp>[1].Str,
text => $sub<text>.Str
}})
!! Nil;
}


method TOP($/) {
sub adjust-time($time, $seconds) {
@.subtitles = $<subtitle>».made;
my ($time_str, $milliseconds_str) = $time.split(',');
make @.subtitles
my (\hh, \mm, \ss) = $time_str.split(':')>>.Int;
my $milliseconds = $milliseconds_str.Int;
my $datetime = DateTime.new(:year, :month, :day,
:hour(hh), :minute(mm), :second(ss));
given $datetime .= later(:seconds($seconds)) {
return sprintf('%02d:%02d:%02d,%03d',.hour,.minute,.second,$milliseconds)
}
}
}


method subtitle($/) {
sub adjust-subtitles(@subtitles, Int $seconds) {
make {
@subtitles.map({ $_<start> = adjust-time($_<start>, $seconds);
$_<end> = adjust-time($_<end> , $seconds);
index => $<index>.Str,
start => $<timecode><timestamp>[0].made,
$_ });
end => $<timecode><timestamp>[1].made,
text => $<text>.made,
}
}

method timestamp($/) { make $/.Str }

method text($/) { make $<line>.join("\n") }
}
}


class SubtitleAdjuster {
sub format-srt(@subtitles) {

@subtitles.map({
method adjust-time($time, $seconds) {
$_<index> ~ "\n" ~ $_<start> ~ " --> " ~ $_<end> ~ "\n" ~ $_<text> ~ "\n"
my ($time-str, $milliseconds-str) = $time.split(',');
}).join("\n");
my (\hh, \mm, \ss) = $time-str.split(':')>>.Int;
my \mls = $milliseconds-str.Int;
my $datetime = DateTime.new( :year, :month, :day,
:hour(hh), :minute(mm), :second(ss));
given $datetime .= later(:seconds($seconds)) {
return sprintf('%02d:%02d:%02d,%03d', .hour, .minute, .second, mls)
}
}

method adjust-subtitles(@subtitles, Int $seconds) {
@subtitles.map({
$_<start> = self.adjust-time($_<start>, $seconds);
$_<end> = self.adjust-time($_<end>, $seconds);
$_;
});
}

method format-srt(@subtitles) {
@subtitles.map({
$_<index> ~ "\n"
~ $_<start> ~ " --> " ~ $_<end> ~ "\n"
~ $_<text> ~ "\n"
}).join("\n");
}
}
}


my @subtitles = parse-srt($*IN.slurp) or die;
my $srt-content = $*IN.slurp;
my $parsed = SRT.parse($srt-content, :actions(SRT::Actions.new));
my @subtitles = $parsed.made;

my $adjuster = SubtitleAdjuster.new;


for 9, -9 -> \N {
for 9, -9 -> \N {
my @adjusted-subtitles = adjust-subtitles(@subtitles.deepmap(*.clone), N);
my @adjusted-subtitles = $adjuster.adjust-subtitles(@subtitles.deepmap(*.clone), N);
say "Original subtitle adjusted by {N.fmt('%+d')} seconds.";
say "Original subtitle adjusted by {N.fmt('%+d')} seconds.";
say format-srt(@adjusted-subtitles);
say $adjuster.format-srt(@adjusted-subtitles);
}</syntaxhighlight>
}</syntaxhighlight>


You may [https://ato.pxeger.com/run?1=jVbdbts2FAZ2NfApzjIHllNakfwvJ3FTbCuWXaRFG2AXdTewFm2rkUiDpJ0ahfsiu-nF9hS722P0EfYUO9Sf6SYtJsAydc75Pp4_HumPPxW7XX_8-NfazNujT9_-slAsy5iCly9u4D18D6mc-Qu5OV0prrnaMJNIcRoni8Sw9HQuVcaMPp3Hsf0FQdAfRL5emiwlAGDkLRdw8-w5Mv0G53r9xiQm5ZNHcAxTAQ3Y7a0qJZqeJyLm7ybW5NwkGZ_JmJdP_J2xq8cuMrdG2DR-5IorpCW0a21YtppAE9pte3dln6FyaU4IJyfQgea4-fCaVuvuAQU6aTdNE1GH6qit2Krbr6bi9cS6vCNkljKtbc7H4yczm2KNJkum4dKvEqPPiCXJuFnK2CbVa5y24L2V4eXYwQU09rn-528_YzE_K-0ydstdYyveucSV5oA9R1UPeBUpv5jgRkWt_JdG0b0eM6hMoa8L6CT8VfA6d8pBcBHj_cuI8B4iT3OJsG1xoN_di6vmKgIrQmqcWsc_M0SyA5uikP5bmQjvaCqOWgclK9P1JH671oYrzFLuQknGcnHbbu417J1CQ2N0Itb77EK2hULb1phGaGRJmialmRW1bEmt3terNDEeNl7rzAVPl0sK0yzDm9a1tYVWiHGzNZn4V8K4uGmWanCui_tbfw5pxMxwS47GP-Lyxnol-J0H4y1n6Pw4k8KgN-OYbZ1qfeUaL-Vaectly4ITsTbcyzL7ULjhYUT7aBfJBs_Q3gv_AlJcK6-01l6d35bbsaC4WSscMyuVCDP3msdBJx7XN3ocdOMmBd_6gn-FH7goyChgploV2_3mKstcnyrvsl5SwAw-UPS9BTbuynNcbfx-np-fCaZY83TuHzRRpXQa6ewAiydpktfyIaxVfglZPewK8UGAxaBva2Wc0P5nMOU0_wD28Ow1H5xAUZeP5aNCmofwoH3xAjhQ7VrO0Sw9R99tr6K7bQzUcKwA9vbJ1bWv07VaneXaFVOax6jAsevnD56LwAZkxSj23Llsm932IzJcHozcgq4ctvkGrJoJF_fGhGVBK0wrRBTaEWDw0-sin5a5hMbtgy0qQv8r_ebHnK9sEU78WSoFx4N0XaRFsy0cPVP46hYs3b9vq63gzRbeX_vzDKfF8aO42dpB2Sb-UY3fu-B2xH1vccdd8UlRfll8_PTNvyEJgnEQjrsh7feDvOClYEC7vSF5imcP3tgBJAXYaaKBLSQlZslhnihtcCAr-_ZMkznPW1L7BEiH1Cz9ft-h7XVoEEbkaQ6dMZwWBZNe-r6PS5wGqbxLt0Tig3JYgW9kusFiEtIlNVfY67nkXRoNI3KDSI4gnBXWeyZm-JaRSuMOhPSIa-uC-3QUjQga5W7NlcwKvwjpV5gB7XQ7LmZIB8GI_LThaot1pTCTCGX43tTcRpZgMsiA1MbDbtdB9wPaHYTkBxyDbMblWsPNVjEhpGZrtbbQIakth92BC-3Q3mhEnnIlZwkivyNkVNmOaNB1U46C0SAiL3hMCYkqq4h2gr0znXEQ0ABz91yKBZKFASnFHdrvBa4d5i2KyJUWTZNHCAwWfHYrHyMqrFA92gsHLmqIgoj8LO-Ap5pj5QVcIc4gOuzjVxh-krZf4PdLIsBWz5J1SI3tH7gahjTojciviVkWBY43tsb2M2G2FDKViy1OeNBLTOYtJAZieSf8ouf_Aw) Attempt This Online!]
You may [https://ato.pxeger.com/run?1=jVbdbts2FAZ2M4BPcZI5sJzSimRZtuUkToFtwXKTFmmAXdRdoVi0rUYiDZJ2agTei-wmF9tL9RH2FDvUv9Osm4Ao1NH3nZ_vHJH-408Z3q-fnv5a63l39OV7dyHDNA0lvLu5hUf4ARIxsxdic7KSTDG5CXUs-EkUL2IdJidzIdNQq5N5FJk_x3H8QWCrpU4TAgBa3DMOt2_eoqff4Eyt73SsEzZ5BUcw5dCCXY0qXyL0LOYR-zwxkDMdp2wmIlY8sc_arC6azAyNtGn0qmkumcahWSsdpqsJtKHbNfem7Rkrs2YO4fgYetAet19e03Lt7bnAJE3QJOZVqY3Xxmxed99P-YeJSXlHCFYPq1Aq1lVSWy28dWeCa8Z1Bx4NN91CKwNEcG56Y2cP-8hTA5RMryWvwMaE18VFaam7YKfhykItWib4Yx6munJR8TrPAUVP7Hda0j0giiV1E1h1rKHwe-fD10zGo3zxTab7AjNTeI9p5sLgathu1ykeDg7gOk5OyQ5yncPo01rprolhtcydohMMzCNVi52_-agwNLTSOEniAmJMHexB9t5WqyTWFg5CLr4hTpdLCtM0xZtSFdLQSvS43ZlM7CuuS85eAMN4HnAPHIWaGZcI_AmXtyYPzh6s8ZaFmK25ximOxDJfwzgKtxT2BHzhGi_FWlrLZYciO-Zrzaw0NQ95GhbWkte4iDc4xXUW9jkkuJZWgVRWpWanGqpiKtVKxlzPrfaR04vG1Y0eOV7UprZJgdp5dGrnXuieGFlPqy-m6GQ50cp6XS0poGTP-1q_zmb_EVofz7L5naCWe2NR2hujcfqigojEOZ6YWXzuIbf_Dw__0Zl6pNFDUXm-8WabRV3Uv1RZRsWUio31dzic8kP8V9ePpmxjLKxZ7k1YvvPmlqwHHfuTiLllnvO0cDTryKhGYzs7vrq2VbKWqw4ICVHMTgnBCiCg0A0Ao06vqw_vda4ii7pNZ9_otB0xtjKFHtuzRHCGM3udS63CLRy-kXhW8TCpD5gyANxt4fHanqf4SR69itqdHRSdsg8rflPorzMzlecnZ3GAPn357m-XOM7YcceeS33fyVQtDAPq9YfkEqcc7sxQCw7mm1UQLgQleslgHkulAc9fc0gk8ZxlCSibAOmRyovv-w23_R513IBcZtRZiJ9k7kktbdvGJX52iXhItkTgg2x4BbYRyYZFNiEeqXy5_X7TuUeDYUBukcmQhHulyT7kM9yfhVQYgZA-aWKbZJ-OghFBUJbWXIo0z4sQv-QMaM_rNTlDOnBG5OcNk1vsJoWZQGqIZ4ViprIYxSADUoGHntdg-w71Bi75EfebcMbEWsHtVoacCxWu5dpQh6RCDr1Bk9qj_dGIXDIpZjEyDwgZldgRdbym5GgYDQJywyJKSFCiAtpz6mR6Y8ehDmr3VvAFOnMdUph71O87TRzqFgTkSvG2ziqEEBZsdi8ukOWWrD7tu4Mma4iGgPwiHoAlimHnOVwhTyPb9fHHBv7y6t7gIR5zMN0zznqk4vp7qboudfoj8musl3mDo43pcYRH7WzJRSIWeIRcgVqimPcQa4jEA7fzmf8H Attempt This Online!]


=={{header|Rust}}==
=={{header|Rust}}==