#!/usr/bin/env python3
"""Apply flashback-prologue reorder to Riddick Unjinxed.kdenlive and regen shifted subs."""
from __future__ import annotations
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent
sys.path.insert(0, str(ROOT.parent.parent / "scripts"))
from kdenlive_from_subs import Cue, build_ass, build_shifted_srt, parse_srt # noqa: E402
KDENLIVE = ROOT / "Riddick (2013) - Unjinxed.kdenlive"
SRT = ROOT / "Riddick (2013) - Unjinxed.srt"
# Kept segments (source seconds) — prologue + main + tail from existing playlist2
KEPT_NEW_HEAD: list[tuple[float, float]] = [
(10 * 60 + 54.487, 13 * 60 + 25.067),
(15 * 60 + 50.717, 22 * 60 + 51.536),
(1 * 60 + 13.573, 10 * 60 + 54.487),
(22 * 60 + 51.536, 24 * 60 + 3.733),
(24 * 60 + 3.733, 40 * 60 + 50.342),
]
TAIL_ENTRIES = """
4
1
1
brightness
fade_from_black
00:00:00.000=0;00:00:06.965=1
0
4
4
1
1
brightness
fade_from_black
00:00:00.000=0;00:00:03.086=1
0
4
1
1
brightness
fade_from_black
00:00:00.000=0;00:00:05.172=1
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
4
1
1
brightness
fade_to_black
00:00:00.000=1;00:00:02.920=0
0
4
1
1
brightness
fade_from_black
00:00:00.000=0;00:00:06.298=1
0
4
"""
def tc_to_sec(tc: str) -> float:
h, m, rest = tc.split(":")
s, ms = rest.split(".")
return int(h) * 3600 + int(m) * 60 + int(s) + int(ms) / 1000.0
def sec_to_tc(sec: float) -> str:
h = int(sec // 3600)
sec -= h * 3600
m = int(sec // 60)
sec -= m * 60
s = int(sec)
ms = int(round((sec - s) * 1000))
if ms >= 1000:
ms = 0
s += 1
return f"{h:02d}:{m:02d}:{s:02d}.{ms:03d}"
TAIL_KEPT: list[tuple[float, float]] = [
(44 * 60 + 11.094, 55 * 60 + 17.893),
(55 * 60 + 37.955, 64 * 60 + 22.147),
(66 * 60 + 42.0, 68 * 60 + 2.669),
(68 * 60 + 59.643, 70 * 60 + 30.113),
(74 * 60 + 19.853, 82 * 60 + 34.493),
(82 * 60 + 34.534, 82 * 60 + 44.294),
(84 * 60 + 23.273, 84 * 60 + 36.787),
(84 * 60 + 36.828, 84 * 60 + 38.830),
(84 * 60 + 40.874, 84 * 60 + 43.168),
(84 * 60 + 43.210, 84 * 60 + 48.632),
(84 * 60 + 53.720, 85 * 60 + 25.275),
(85 * 60 + 27.319, 85 * 60 + 45.337),
(86 * 60 + 16.391, 86 * 60 + 27.569),
(86 * 60 + 27.611, 88 * 60 + 14.514),
(88 * 60 + 36.578, 89 * 60 + 25.150),
(89 * 60 + 58.684, 90 * 60 + 23.357),
(91 * 60 + 27.819, 96 * 60 + 4.046),
(97 * 60 + 7.591, 98 * 60 + 36.995),
(98 * 60 + 37.037, 98 * 60 + 55.764),
(99 * 60 + 6.840, 99 * 60 + 13.305),
(99 * 60 + 32.783, 99 * 60 + 40.916),
(99 * 60 + 40.958, 100 * 60 + 14.223),
(100 * 60 + 32.783, 101 * 60 + 27.444),
(101 * 60 + 38.497, 105 * 60 + 10.969),
(105 * 60 + 21.563, 119 * 60 + 2.711),
(119 * 60 + 9.426, 119 * 60 + 31.198),
(119 * 60 + 31.240, 126 * 60 + 47.631),
]
def build_playlist2() -> str:
head = """
4
4
1
1
brightness
fade_to_black
00:00:00.000=1;00:00:02.460=0
4
1
1
brightness
fade_from_black
00:00:00.000=0;00:00:03.086=1
0
4
4
1
1
brightness
fade_to_black
00:00:00.000=1;00:00:01.460=0
"""
return head + TAIL_ENTRIES + " \n"
def total_out_sec(kept: list[tuple[float, float]]) -> float:
return sum(b - a for a, b in kept)
def main() -> None:
text = KDENLIVE.read_text(encoding="utf-8")
new_pl = build_playlist2()
text, n = re.subn(
r" .*?\n",
new_pl,
text,
count=1,
flags=re.DOTALL,
)
if n != 1:
raise SystemExit("playlist2 replace failed")
all_kept = KEPT_NEW_HEAD + TAIL_KEPT
out_dur = total_out_sec(all_kept)
out_tc = sec_to_tc(out_dur - 1 / 24) # frame-ish trim for MLT out
text = re.sub(
r'({out_tc}\2",
text,
count=1,
)
text = re.sub(
r'({out_tc}\2",
text,
count=1,
)
dur_prop = out_tc.replace(".", ":")
if len(dur_prop.split(":")[-1]) > 3:
parts = dur_prop.split(":")
dur_prop = f"{parts[0]}:{parts[1]}:{parts[2]}.{parts[3][:3]}" if len(parts) > 3 else dur_prop
# kdenlive:duration uses HH:MM:SS.mmm style in file
dur_kd = out_tc
text = re.sub(
r'(\s*)[^<]+',
rf"\g<1>{dur_kd}",
text,
count=1,
)
text = re.sub(
r'({out_tc}\2",
text,
count=1,
)
track_pat = r'()'
text = re.sub(track_pat, rf"\g<1>{out_tc}\2", text, count=1)
KDENLIVE.write_text(text, encoding="utf-8")
print(f"Updated {KDENLIVE.name} duration ~{out_tc}")
cues = parse_srt(SRT)
all_kept_full = KEPT_NEW_HEAD + TAIL_KEPT
shifted = build_shifted_srt(cues, all_kept_full)
ass = build_ass(cues, all_kept_full)
(ROOT / "Riddick (2013) - Unjinxed.kdenlive.shifted.srt").write_text(
shifted, encoding="utf-8"
)
(ROOT / "Riddick (2013) - Unjinxed.kdenlive.ass").write_text(ass, encoding="utf-8")
print("Wrote shifted SRT and ASS")
if __name__ == "__main__":
main()