Skip to content

Commit 3520c42

Browse files
committed
WIP: reversing videos, etc.
1 parent 1720a7d commit 3520c42

File tree

5 files changed

+86
-10
lines changed

5 files changed

+86
-10
lines changed

.pre-commit-config.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ repos:
55
- id: check-yaml
66
- id: end-of-file-fixer
77
- id: trailing-whitespace
8+
- repo: https://github.com/psf/black
9+
rev: 22.6.0
10+
hooks:
11+
- id: black
812
- repo: https://github.com/pycqa/isort
913
rev: 5.10.1
1014
hooks:

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
![PyPI - Downloads](https://img.shields.io/pypi/dm/manim-slides)
44
# Manim Slides
55

6-
Tool for live presentations using either [manim](http://3b1b.github.io/manim/) or [manim-community](https://www.manim.community/).
6+
Tool for live presentations using either [manim-community](https://www.manim.community/). Currently, support for 3b1b's manim is not planned.
77

88
> **_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.
99
@@ -124,7 +124,6 @@ Here are a few things that I implemented (or that I'm planning to implement) on
124124
- [x] Config file path can be manually set
125125
- [ ] Play animation in reverse [#9](https://github.com/galatolofederico/manim-presentation/issues/9)
126126
- [x] Handle 3D scenes out of the box
127-
- [ ] Can work with both community and 3b1b versions (not tested)
128127
- [ ] Generate docs online
129128
- [ ] Fix the quality problem on Windows platforms with `fullscreen` flag
130129

manim_slides/present.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .commons import config_path_option
1313
from .config import Config
1414
from .defaults import CONFIG_PATH, FOLDER_PATH
15+
from .slide import reverse_video_path
1516

1617

1718
class State(Enum):
@@ -44,7 +45,7 @@ class Presentation:
4445
def __init__(self, config, last_frame_next: bool = False):
4546
self.last_frame_next = last_frame_next
4647
self.slides = config["slides"]
47-
self.files = config["files"]
48+
self.files = [reverse_video_path(path) for path in config["files"]]
4849

4950
self.lastframe = []
5051

@@ -82,6 +83,9 @@ def prev(self):
8283
self.current_slide_i = max(0, self.current_slide_i - 1)
8384
self.rewind_slide()
8485

86+
def reserve_slide(self):
87+
pass
88+
8589
def rewind_slide(self):
8690
self.current_animation = self.current_slide["start_animation"]
8791
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
@@ -275,8 +279,28 @@ def quit(self):
275279
sys.exit()
276280

277281

282+
"""
278283
@click.command()
279-
@click.argument("scenes", nargs=-1)
284+
@click.option(
285+
"--folder",
286+
default=FOLDER_PATH,
287+
type=click.Path(exists=True, file_okay=False),
288+
help="Set slides folder.",
289+
)
290+
"""
291+
@click.help_option("-h", "--help")
292+
def list_scenes(folder):
293+
scenes = []
294+
295+
for file in os.listdir(folder):
296+
if file.endswith(".json"):
297+
scenes.append(os.path.basename(file)[:-4])
298+
299+
return scenes
300+
301+
302+
@click.command()
303+
@click.option("--scenes", nargs=-1, prompt=True)
280304
@config_path_option
281305
@click.option(
282306
"--folder",
@@ -295,6 +319,20 @@ def quit(self):
295319
def present(scenes, config_path, folder, start_paused, fullscreen, last_frame_next):
296320
"""Present the different scenes"""
297321

322+
if len(scenes) == 0:
323+
print("ICI")
324+
scene_choices = list_scenes(folder)
325+
326+
scene_choices = dict(enumerate(scene_choices, start=1))
327+
choices = [str(i) for i in scene_choices.keys()]
328+
329+
def value_proc(value: str):
330+
raise ValueError("Value:")
331+
332+
print(scene_choices)
333+
334+
scenes = click.prompt("Choose a scene", value_proc=value_proc)
335+
298336
presentations = list()
299337
for scene in scenes:
300338
config_file = os.path.join(folder, f"{scene}.json")

manim_slides/slide.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
11
import json
22
import os
3+
import platform
34
import shutil
5+
import subprocess
46

5-
from manim import Scene, ThreeDScene, config
7+
from manim import Scene, ThreeDScene, config, logger
8+
from tqdm import tqdm
9+
10+
try: # For manim<v0.16.0.post0
11+
from manim.constants import FFMPEG_BIN as ffmpeg_executable
12+
except ImportError:
13+
ffmpeg_executable = config.ffmpeg_executable
614

715
from .defaults import FOLDER_PATH
816

917

18+
def reverse_video_path(src: str) -> str:
19+
file, ext = os.path.splitext(src)
20+
return f"{file}_reversed{ext}"
21+
22+
23+
def reverse_video_file(src: str, dst: str):
24+
command = [config.ffmpeg_executable, "-i", src, "-vf", "reverse", dst]
25+
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
26+
process.communicate()
27+
28+
1029
class Slide(Scene):
1130
def __init__(self, *args, output_folder=FOLDER_PATH, **kwargs):
1231
super().__init__(*args, **kwargs)
@@ -79,14 +98,31 @@ def render(self, *args, **kwargs):
7998
os.mkdir(scene_files_folder)
8099

81100
files = list()
82-
for src_file in self.renderer.file_writer.partial_movie_files:
101+
for src_file in tqdm(
102+
self.renderer.file_writer.partial_movie_files,
103+
desc=f"Copying animation files to '{scene_files_folder}' and generating reversed animations",
104+
leave=config["progress_bar"] == "leave",
105+
ascii=True if platform.system() == "Windows" else None,
106+
disable=config["progress_bar"] == "none",
107+
):
83108
dst_file = os.path.join(scene_files_folder, os.path.basename(src_file))
84109
shutil.copyfile(src_file, dst_file)
110+
rev_file = reverse_video_path(dst_file)
111+
reverse_video_file(src_file, rev_file)
85112
files.append(dst_file)
86113

87-
f = open(os.path.join(self.output_folder, "%s.json" % (scene_name,)), "w")
114+
logger.info(
115+
f"Copied {len(files)} animations to '{os.path.abspath(scene_files_folder)}' and generated reversed animations"
116+
)
117+
118+
slide_path = os.path.join(self.output_folder, "%s.json" % (scene_name,))
119+
120+
f = open(slide_path, "w")
88121
json.dump(dict(slides=self.slides, files=files), f)
89122
f.close()
123+
logger.info(
124+
f"Slide '{scene_name}' configuration written in '{os.path.abspath(slide_path)}'"
125+
)
90126

91127

92128
class ThreeDSlide(Slide, ThreeDScene):

setup.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
import setuptools
44

5-
sys.path.append("manim_slides") # To avoid importing manim, which may not be installed
6-
7-
from __version__ import __version__ as version
5+
from .__version__ import __version__ as version
86

97
if sys.version_info < (3, 7):
108
raise RuntimeError("This package requires Python 3.7+")
@@ -31,6 +29,7 @@
3129
install_requires=[
3230
"click>=8.0",
3331
"click-default-group>=1.2",
32+
"manim",
3433
"numpy>=1.19.3",
3534
"pydantic>=1.9.1",
3635
"opencv-python>=4.6",

0 commit comments

Comments
 (0)