diff --git a/CHANGELOG.md b/CHANGELOG.md index b402f4b5..59754cda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 (unreleased)= ## [Unreleased](https://github.com/jeertmans/manim-slides/compare/5.1.7...HEAD) +(unreleased-fixed)= +### Fixed + +- Fix combining assets from multiple scenes to avoid filename collision. + [#429](https://github.com/jeertmans/manim-slides/pull/429) + (v5.1.7)= ## [v5.1.7](https://github.com/jeertmans/manim-slides/compare/v5.1.6...v5.1.7) diff --git a/manim_slides/config.py b/manim_slides/config.py index 3fd4f912..93dd69df 100644 --- a/manim_slides/config.py +++ b/manim_slides/config.py @@ -324,15 +324,19 @@ def to_file(self, path: Path) -> None: f.write(self.model_dump_json(indent=2)) def copy_to( - self, folder: Path, use_cached: bool = True, include_reversed: bool = True + self, + folder: Path, + use_cached: bool = True, + include_reversed: bool = True, + prefix: str = "", ) -> "PresentationConfig": """Copy the files to a given directory.""" for slide_config in self.slides: file = slide_config.file rev_file = slide_config.rev_file - dest = folder / file.name - rev_dest = folder / rev_file.name + dest = folder / f"{prefix}{file.name}" + rev_dest = folder / f"{prefix}{rev_file.name}" slide_config.file = dest slide_config.rev_file = rev_dest diff --git a/manim_slides/convert.py b/manim_slides/convert.py index aba86c0e..774f7998 100644 --- a/manim_slides/convert.py +++ b/manim_slides/convert.py @@ -404,8 +404,28 @@ def convert_to(self, dest: Path) -> None: full_assets_dir.mkdir(parents=True, exist_ok=True) - for presentation_config in self.presentation_configs: - presentation_config.copy_to(full_assets_dir, include_reversed=False) + num_presentation_configs = len(self.presentation_configs) + + if num_presentation_configs > 1: + # Prevent possible name collision, see: + # https://github.com/jeertmans/manim-slides/issues/428 + # With ManimCE, this can happen when caching is disabled as filenames are + # 'uncached_000x.mp4' + # With ManimGL, this can easily occur since filenames are just basic integers... + num_digits = len(str(num_presentation_configs - 1)) + + def prefix(i: int) -> str: + return f"s{i:0{num_digits}d}_" + + else: + + def prefix(i: int) -> str: + return "" + + for i, presentation_config in enumerate(self.presentation_configs): + presentation_config.copy_to( + full_assets_dir, include_reversed=False, prefix=prefix(i) + ) dest.parent.mkdir(parents=True, exist_ok=True) diff --git a/tests/test_convert.py b/tests/test_convert.py index 791dfeac..2cf4d0e4 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -153,6 +153,28 @@ def test_revealjs_converter( file_contents = Path(out_file).read_text() assert "manim" in file_contents.casefold() + @pytest.mark.parametrize("num_presentation_configs", (1, 2)) + def test_revealjs_multiple_scenes_converter( + self, + tmp_path: Path, + presentation_config: PresentationConfig, + num_presentation_configs: int, + ) -> None: + out_file = tmp_path / "slides.html" + RevealJS( + presentation_configs=[ + presentation_config for _ in range(num_presentation_configs) + ] + ).convert_to(out_file) + assert out_file.exists() + assets_dir = Path(tmp_path / "slides_assets") + assert assets_dir.is_dir() + + got = sum(1 for _ in assets_dir.iterdir()) + expected = num_presentation_configs * len(presentation_config.slides) + + assert got == expected + @pytest.mark.parametrize("frame_index", ("first", "last")) def test_pdf_converter( self, frame_index: str, tmp_path: Path, presentation_config: PresentationConfig