Release / build-and-push (push) Successful in 2m33s
Fixed-layout EPUBs lean on the reading_direction column (the web reader forces book.dir = rtl from it when the file didn't set direction itself), but the scanner never populated it for EPUBs - only ComicInfo fed it. Meanwhile real Japanese EPUBs declare page-progression-direction on the OPF spine, which foliate reads client-side but nothing stored. Read the spine attribute in the structured OPF parser and map it into ReadingDirection in parseOPFContent (EPUB2/3, case-insensitive, plus 'right-to-left'/'left-to-right' spellings); undeclared stays empty rather than forcing ltr, preserving the editor's Auto default. Sidecar OPFs are metadata-only documents without spines, so the Calibre path is a no-op. The merge gap-fill copies an embedded-only direction into a blank sidecar field, and hand-set values keep winning through the existing OverrideReadingDirection protection. Tests: declared rtl/RTL/ltr, undeclared and unknown values staying empty, plus sidecar-wins vs embedded-fills merge cases. Existing manga EPUBs declaring rtl (verified live in-library) pick the value up on their next scan, feeding the API and reader config mobile clients consume.