diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b4554a7..8ed870d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,6 +5,10 @@ repos: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace +- repo: https://github.com/psf/black + rev: 22.6.0 + hooks: + - id: black - repo: https://github.com/pycqa/isort rev: 5.10.1 hooks: diff --git a/README.md b/README.md index a6919b6..61b34d7 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ![PyPI - Downloads](https://img.shields.io/pypi/dm/manim-slides) # Manim Slides -Tool for live presentations using either [manim](http://3b1b.github.io/manim/) or [manim-community](https://www.manim.community/). +Tool for live presentations using either [manim-community](https://www.manim.community/). Currently, support for 3b1b's manim is not planned. > **_NOTE:_** This project is a fork of [`manim-presentation`](https://github.com/galatolofederico/manim-presentation). Since the project seemed to be inactive, I decided to create my own fork to deploy new features more rapidly. @@ -124,7 +124,6 @@ Here are a few things that I implemented (or that I'm planning to implement) on - [x] Config file path can be manually set - [ ] Play animation in reverse [#9](https://github.com/galatolofederico/manim-presentation/issues/9) - [x] Handle 3D scenes out of the box -- [ ] Can work with both community and 3b1b versions (not tested) - [ ] Generate docs online - [ ] Fix the quality problem on Windows platforms with `fullscreen` flag diff --git a/manim_slides/present.py b/manim_slides/present.py index be48d40..f68b7e4 100644 --- a/manim_slides/present.py +++ b/manim_slides/present.py @@ -12,6 +12,7 @@ import numpy as np from .commons import config_path_option from .config import Config from .defaults import CONFIG_PATH, FOLDER_PATH +from .slide import reverse_video_path class State(Enum): @@ -44,7 +45,7 @@ class Presentation: def __init__(self, config, last_frame_next: bool = False): self.last_frame_next = last_frame_next self.slides = config["slides"] - self.files = config["files"] + self.files = [reverse_video_path(path) for path in config["files"]] self.lastframe = [] @@ -82,6 +83,9 @@ class Presentation: self.current_slide_i = max(0, self.current_slide_i - 1) self.rewind_slide() + def reserve_slide(self): + pass + def rewind_slide(self): self.current_animation = self.current_slide["start_animation"] self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, 0) @@ -275,8 +279,28 @@ class Display: sys.exit() +""" @click.command() -@click.argument("scenes", nargs=-1) +@click.option( + "--folder", + default=FOLDER_PATH, + type=click.Path(exists=True, file_okay=False), + help="Set slides folder.", +) +""" +@click.help_option("-h", "--help") +def list_scenes(folder): + scenes = [] + + for file in os.listdir(folder): + if file.endswith(".json"): + scenes.append(os.path.basename(file)[:-4]) + + return scenes + + +@click.command() +@click.option("--scenes", nargs=-1, prompt=True) @config_path_option @click.option( "--folder", @@ -295,6 +319,20 @@ class Display: def present(scenes, config_path, folder, start_paused, fullscreen, last_frame_next): """Present the different scenes""" + if len(scenes) == 0: + print("ICI") + scene_choices = list_scenes(folder) + + scene_choices = dict(enumerate(scene_choices, start=1)) + choices = [str(i) for i in scene_choices.keys()] + + def value_proc(value: str): + raise ValueError("Value:") + + print(scene_choices) + + scenes = click.prompt("Choose a scene", value_proc=value_proc) + presentations = list() for scene in scenes: config_file = os.path.join(folder, f"{scene}.json") diff --git a/manim_slides/slide.py b/manim_slides/slide.py index 88999ae..b30c51e 100644 --- a/manim_slides/slide.py +++ b/manim_slides/slide.py @@ -1,12 +1,31 @@ import json import os +import platform import shutil +import subprocess -from manim import Scene, ThreeDScene, config +from manim import Scene, ThreeDScene, config, logger +from tqdm import tqdm + +try: # For manim str: + file, ext = os.path.splitext(src) + return f"{file}_reversed{ext}" + + +def reverse_video_file(src: str, dst: str): + command = [config.ffmpeg_executable, "-i", src, "-vf", "reverse", dst] + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process.communicate() + + class Slide(Scene): def __init__(self, *args, output_folder=FOLDER_PATH, **kwargs): super().__init__(*args, **kwargs) @@ -79,14 +98,31 @@ class Slide(Scene): os.mkdir(scene_files_folder) files = list() - for src_file in self.renderer.file_writer.partial_movie_files: + for src_file in tqdm( + self.renderer.file_writer.partial_movie_files, + desc=f"Copying animation files to '{scene_files_folder}' and generating reversed animations", + leave=config["progress_bar"] == "leave", + ascii=True if platform.system() == "Windows" else None, + disable=config["progress_bar"] == "none", + ): dst_file = os.path.join(scene_files_folder, os.path.basename(src_file)) shutil.copyfile(src_file, dst_file) + rev_file = reverse_video_path(dst_file) + reverse_video_file(src_file, rev_file) files.append(dst_file) - f = open(os.path.join(self.output_folder, "%s.json" % (scene_name,)), "w") + logger.info( + f"Copied {len(files)} animations to '{os.path.abspath(scene_files_folder)}' and generated reversed animations" + ) + + slide_path = os.path.join(self.output_folder, "%s.json" % (scene_name,)) + + f = open(slide_path, "w") json.dump(dict(slides=self.slides, files=files), f) f.close() + logger.info( + f"Slide '{scene_name}' configuration written in '{os.path.abspath(slide_path)}'" + ) class ThreeDSlide(Slide, ThreeDScene): diff --git a/setup.py b/setup.py index c7ec056..10c910e 100644 --- a/setup.py +++ b/setup.py @@ -2,9 +2,7 @@ import sys import setuptools -sys.path.append("manim_slides") # To avoid importing manim, which may not be installed - -from __version__ import __version__ as version +from .__version__ import __version__ as version if sys.version_info < (3, 7): raise RuntimeError("This package requires Python 3.7+") @@ -31,6 +29,7 @@ setuptools.setup( install_requires=[ "click>=8.0", "click-default-group>=1.2", + "manim", "numpy>=1.19.3", "pydantic>=1.9.1", "opencv-python>=4.6",