3b1b-manim/manimlib/utils/init_config.py
Grant Sanderson 94f6f0aa96
Cleaner local caching of Tex/Text data, and partially cleaned up configuration (#2259)
* Remove print("Reloading...")

* Change where exception mode is set, to be quieter

* Add default fallback monitor for when no monitors are detected

* Have StringMobject work with svg strings rather than necessarily writing to file

Change SVGMobject to allow taking in a string of svg code as an input

* Add caching functionality, and have Tex and Text both use it for saved svg strings

* Clean up tex_file_writing

* Get rid of get_tex_dir and get_text_dir

* Allow for a configurable cache location

* Make caching on disk a decorator, and update implementations for Tex and Text mobjects

* Remove stray prints

* Clean up how configuration is handled

In principle, all we need here is that manim looks to the default_config.yaml file, and updates it based on any local configuration files, whether in the current working directory or as specified by a CLI argument.

* Make the default size for hash_string an option

* Remove utils/customization.py

* Remove stray prints

* Consolidate camera configuration

This is still not optimal, but at least makes clearer the way that importing from constants.py kicks off some of the configuration code.

* Factor out configuration to be passed into a scene vs. that used to run a scene

* Use newer extract_scene.main interface

* Add clarifying message to note what exactly is being reloaded

* Minor clean up

* Minor clean up

* If it's worth caching to disk, then might as well do so in memory too during development

* No longer any need for custom hash_seeds in Tex and Text

* Remove display_during_execution

* Get rid of (no longer used) mobject_data directory reference

* Remove get_downloads_dir reference from register_font

* Update where downloads go

* Easier use of subdirectories in configuration

* Add new pip requirements
2024-12-05 14:51:14 -08:00

164 lines
5.9 KiB
Python

from __future__ import annotations
import importlib
import inspect
import os
import yaml
from rich import box
from rich.console import Console
from rich.prompt import Confirm
from rich.prompt import Prompt
from rich.rule import Rule
from rich.table import Table
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Any
def get_manim_dir() -> str:
manimlib_module = importlib.import_module("manimlib")
manimlib_dir = os.path.dirname(inspect.getabsfile(manimlib_module))
return os.path.abspath(os.path.join(manimlib_dir, ".."))
def remove_empty_value(dictionary: dict[str, Any]) -> None:
for key in list(dictionary.keys()):
if dictionary[key] == "":
dictionary.pop(key)
elif isinstance(dictionary[key], dict):
remove_empty_value(dictionary[key])
def init_customization() -> None:
configuration = {
"directories": {
"mirror_module_path": False,
"base": "",
"subdirs": {
"output": "videos",
"raster_images": "raster_images",
"vector_images": "vector_images",
"sounds": "sounds",
"data": "data",
"downloads": "downloads",
}
},
"universal_import_line": "from manimlib import *",
"style": {
"tex_template": "",
"font": "Consolas",
"background_color": "",
},
"window_position": "UR",
"window_monitor": 0,
"full_screen": False,
"break_into_partial_movies": False,
"camera_resolutions": {
"low": "854x480",
"medium": "1280x720",
"high": "1920x1080",
"4k": "3840x2160",
"default_resolution": "",
},
"fps": 30,
}
console = Console()
console.print(Rule("[bold]Configuration Guide[/bold]"))
# print("Initialize configuration")
try:
scope = Prompt.ask(
" Select the scope of the configuration",
choices=["global", "local"],
default="local"
)
console.print("[bold]Directories:[/bold]")
dir_config = configuration["directories"]
dir_config["base"] = Prompt.ask(
" What base directory should manim use for reading/writing video and images? [prompt.default](optional, default is none)",
default="",
show_default=False
)
dir_config["subdirs"]["output"] = Prompt.ask(
" Within that base directory, which subdirectory should manim [bold]output[/bold] video and image files to?" + \
" [prompt.default](optional, default is \"videos\")",
default="videos",
show_default=False
)
dir_config["subdirs"]["raster_images"] = Prompt.ask(
" Within that base directory, which subdirectory should manim look for raster images (.png, .jpg)" + \
" [prompt.default](optional, default is \"raster_images\")",
default="raster_images",
show_default=False
)
dir_config["subdirs"]["vector_images"] = Prompt.ask(
" Within that base directory, which subdirectory should manim look for raster images (.svg, .xdv)" + \
" [prompt.default](optional, default is \"vector_images\")",
default="vector_images",
show_default=False
)
dir_config["subdirs"]["sounds"] = Prompt.ask(
" Within that base directory, which subdirectory should manim look for sound files (.mp3, .wav)" + \
" [prompt.default](optional, default is \"sounds\")",
default="sounds",
show_default=False
)
dir_config["subdirs"]["downloads"] = Prompt.ask(
" Within that base directory, which subdirectory should manim output downloaded files" + \
" [prompt.default](optional, default is \"downloads\")",
default="downloads",
show_default=False
)
console.print("[bold]Styles:[/bold]")
style_config = configuration["style"]
tex_template = Prompt.ask(
" Select a TeX template to compile a LaTeX source file",
default="default"
)
style_config["tex_template"] = tex_template
style_config["background_color"] = Prompt.ask(
" Which [bold]background color[/bold] do you want [italic](hex code)",
default="#333333"
)
console.print("[bold]Camera qualities:[/bold]")
table = Table(
"low", "medium", "high", "ultra_high",
title="Four defined qualities",
box=box.ROUNDED
)
table.add_row("480p15", "720p30", "1080p60", "2160p60")
console.print(table)
configuration["camera_resolutions"]["default_resolution"] = Prompt.ask(
" Which one to choose as the default rendering quality",
choices=["low", "medium", "high", "ultra_high"],
default="high"
)
write_to_file = Confirm.ask(
"\n[bold]Are you sure to write these configs to file?[/bold]",
default=True
)
if not write_to_file:
raise KeyboardInterrupt
global_file_name = os.path.join(get_manim_dir(), "manimlib", "default_config.yml")
if scope == "global":
file_name = global_file_name
else:
if os.path.exists(global_file_name):
remove_empty_value(configuration)
file_name = os.path.join(os.getcwd(), "custom_config.yml")
with open(file_name, "w", encoding="utf-8") as f:
yaml.dump(configuration, f)
console.print(f"\n:rocket: You have successfully set up a {scope} configuration file!")
console.print(f"You can manually modify it in: [cyan]`{file_name}`[/cyan]")
except KeyboardInterrupt:
console.print("\n[green]Exit configuration guide[/green]")