diff --git a/README.md b/README.md index 003ce5c6..7bbb367a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Manim runs on python 3.7. You can install the python requirements with git clone https://github.com/3b1b/manim.git cd manim pip install -r requirements.txt -python3 extract_scene.py example_scenes.py SquareToCircle -pl +python3 -m manim example_scenes.py SquareToCircle -pl ``` ### Using `virtualenv` and `virtualenvwrapper` @@ -23,7 +23,7 @@ After installing `virtualenv` and `virtualenvwrapper` ```sh git clone https://github.com/3b1b/manim.git mkvirtualenv -a manim -r requirements.txt manim -python3 extract_scene.py example_scenes.py SquareToCircle -pl +python3 -m manim example_scenes.py SquareToCircle -pl ``` ### Using Docker @@ -41,14 +41,14 @@ The image does not contain a copy of the repo. This is intentional, as it allows 4. Render an animation ```sh cd manim -python3 extract_scene.py example_scenes.py SquareToCircle -l +python3 -m manim example_scenes.py SquareToCircle -l ``` Note that the image doesn't have any development tools installed and can't preview animations. Its purpose is building and testing only. ## Using manim Try running the following: ```sh -python3 extract_scene.py example_scenes.py SquareToCircle -pl +python3 -m manim example_scenes.py SquareToCircle -pl ``` The -p is for previewing, meaning the the video file will automatically open when it is done rendering. Use -l for a faster rendering at a lower quality. @@ -69,18 +69,24 @@ Documentation is in progress at [manim.readthedocs.io](https://manim.readthedocs Todd Zimmerman put together a [tutorial](https://talkingphysics.wordpress.com/2018/06/11/learning-how-to-animate-videos-using-manim-series-a-journey/) on getting started with manim, but it uses an outdated version that runs on python 2.7. It may not be fully compatible with the current version of manim, but it does a good job laying out the basics. ### Live Streaming -To live stream your animations, simply assign `IS_LIVE_STREAMING = True` in `constants.py` file and from your Python Interactive Shell (`python3`) import the stream starter with `from stream_starter import *` while under the project directory. This will provide a clean interactive shell to enter your commands. `manim` object is a `Manim()` instance so as soon as you play an animation with `manim.play()` your stream will start. A video player will pop-up and you can broadcast that video using [OBS Studio](https://obsproject.com/) which is the most practical way of streaming with this math animation library. An example: +To live stream your animations, simply run manim with the `--livestreaming` option. -``` ->>> from stream_starter import * -YOUR STREAM IS READY! ->>> circle = Circle() ->>> manim.play(ShowCreation(circle)) -Animation 0: ShowCreationCircle: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 60/60 [00:01<00:00, 37.30it/s] - +```sh +> python -m manim --livestream +Writing to media/videos/scene/scene/1080p30/LiveStreamTemp.mp4 + +Manim is now running in streaming mode. Stream animations by passing +them to manim.play(), e.g. +>>> c = Circle() +>>> manim.play(ShowCreation(c)) + +>>> ``` -It is also possible to stream directly to Twitch. To do that simply assign `IS_STREAMING_TO_TWITCH = True` in `constants.py` file and put your Twitch Stream Key to `TWITCH_STREAM_KEY = "YOUR_STREAM_KEY"` and when you follow the above example the stream will directly start on your Twitch channel(with no audio support). +It is also possible to stream directly to Twitch. To do that simply pass +--livestream and --to-twitch to manim and specify the stream key with +--with-key. Then when you follow the above example the stream will directly +start on your Twitch channel (with no audio support). ## Contributing diff --git a/config.py b/config.py index 9bb4a220..bec4870e 100644 --- a/config.py +++ b/config.py @@ -20,8 +20,6 @@ def parse_cli(): nargs="?", help="Name of the Scene class you want to see", ) - module_location.add_argument("--livestream", action="store_true") - parser.add_argument("--to-twitch", action="store_true") optional_args = [ ("-p", "--preview"), ("-w", "--write_to_movie"), @@ -40,12 +38,33 @@ def parse_cli(): parser.add_argument("-n", "--start_at_animation_number") parser.add_argument("-r", "--resolution") parser.add_argument("-c", "--color") + module_location.add_argument( + "--livestream", + action="store_true", + help="Run in streaming mode", + ) + parser.add_argument( + "--to-twitch", + action="store_true", + help="Stream to twitch", + ) + parser.add_argument( + "--with-key", + dest="twitch_key", + help="Stream key for twitch", + ) args = parser.parse_args() + if args.file is None and not args.livestream: parser.print_help() sys.exit(2) - else: - return args + if args.to_twitch and not args.livestream: + print("You must run in streaming mode in order to stream to twitch") + sys.exit(2) + if args.to_twitch and args.twitch_key is None: + print("Specify the twitch stream key with --with-key") + sys.exit(2) + return args except argparse.ArgumentError as err: print(str(err)) sys.exit(2) diff --git a/constants.py b/constants.py index 5d3cd6ac..431ddfd7 100644 --- a/constants.py +++ b/constants.py @@ -237,3 +237,9 @@ STREAMING_IP = "127.0.0.1" STREAMING_PORT = "2000" STREAMING_CLIENT = "ffplay" STREAMING_URL = f"{STREAMING_PROTOCOL}://{STREAMING_IP}:{STREAMING_PORT}?listen" +STREAMING_CONSOLE_BANNER = """ +Manim is now running in streaming mode. Stream animations by passing +them to manim.play(), e.g. +>>> c = Circle() +>>> manim.play(ShowCreation(c)) +""" diff --git a/manim.py b/manim.py index 15be1acb..c5c814d3 100644 --- a/manim.py +++ b/manim.py @@ -8,4 +8,7 @@ if not args.livestream: config = config.get_configuration(args) extract_scene.main(config) else: - stream_starter.start_livestream(args.to_twitch) + stream_starter.start_livestream( + to_twitch=args.to_twitch, + twitch_key=args.twitch_key, + ) diff --git a/scene/scene.py b/scene/scene.py index b920a42c..cff2df29 100644 --- a/scene/scene.py +++ b/scene/scene.py @@ -53,6 +53,7 @@ class Scene(Container): "end_at_animation_number": None, "livestreaming": False, "to_twitch": False, + "twitch_key": None, } def __init__(self, **kwargs): @@ -658,7 +659,7 @@ class Scene(Container): if self.livestreaming: if self.to_twitch: command += ['-f', 'flv'] - command += ['rtmp://live.twitch.tv/app/' + TWITCH_STREAM_KEY] + command += ['rtmp://live.twitch.tv/app/' + self.twitch_key] else: command += ['-f', 'mpegts'] command += [STREAMING_PROTOCOL + '://' + STREAMING_IP + ':' + STREAMING_PORT] diff --git a/stream_starter.py b/stream_starter.py index 677e80db..709faf88 100644 --- a/stream_starter.py +++ b/stream_starter.py @@ -3,10 +3,11 @@ from time import sleep import code import constants import os +import readline import subprocess -def start_livestream(to_twitch=False): +def start_livestream(to_twitch=False, twitch_key=None): class Manim(): def __new__(cls): @@ -32,6 +33,7 @@ def start_livestream(to_twitch=False): "frame_duration": constants.MEDIUM_QUALITY_FRAME_DURATION, "livestreaming": True, "to_twitch": to_twitch, + "twitch_key": twitch_key, } return Scene(**kwargs) @@ -43,10 +45,9 @@ def start_livestream(to_twitch=False): stderr=FNULL) sleep(3) - manim = Manim() - print("YOUR STREAM IS READY!") variables = globals().copy() variables.update(locals()) shell = code.InteractiveConsole(variables) + shell.push("manim = Manim()") shell.push("from big_ol_pile_of_manim_imports import *") - shell.interact() + shell.interact(banner=constants.STREAMING_CONSOLE_BANNER)