Source code for terminhtml_recorder.recorder
import shutil
from dataclasses import dataclass
from pathlib import Path
from typing import Callable, Union
from playwright.sync_api import Locator, Page, sync_playwright
from terminhtml_recorder.converter import convert_video_to_gif
from terminhtml_recorder.formats import OutputFormat
from terminhtml_recorder.logger import log
from terminhtml_recorder.temp_path import create_temp_path
from terminhtml_recorder.video import Video
[docs]@dataclass
class Recording:
video: Video
format: OutputFormat
[docs] @classmethod
def from_path(cls, path: Path, format: OutputFormat) -> "Recording":
return cls(video=Video.from_path(path), format=format)
@property
def path(self) -> Path:
return self.video.path
[docs] def convert_to(
self,
new_format: OutputFormat,
out_path: Path,
begin_after: float = 1.1,
resize: float = 0.7,
fps: int = 10,
) -> "Recording":
clip = self.video.transform_clip(begin_after, resize)
if new_format == self.format:
shutil.copy(self.path, out_path)
# TODO: need to trim for delay in webm output
return Recording.from_path(path=out_path, format=new_format)
elif new_format == OutputFormat.GIF:
convert_video_to_gif(clip, out_path, fps=fps)
return Recording.from_path(path=out_path, format=new_format)
raise NotImplementedError(
f"Conversion from {self.format} to {new_format} not implemented"
)
[docs]@dataclass
class PageLocators:
speed_up: Locator
speed_down: Locator
restart: Locator
[docs] @classmethod
def from_page(cls, page: Page) -> "PageLocators":
return cls(
speed_up=page.locator("text=►"),
speed_down=page.locator("text=◄"),
restart=page.locator("text=restart ↻"),
)
PageInteractor = Callable[[PageLocators], None]
[docs]def default_page_interactor(page_locators: PageLocators) -> None:
page_locators.restart.wait_for()
[docs]class TerminHTMLRecorder:
[docs] def __init__(self, html: str, interactor: PageInteractor = default_page_interactor):
self.html = html
self.interactor = interactor
[docs] def record(
self,
out_path: Union[str, Path],
format: OutputFormat = OutputFormat.GIF,
begin_after: float = 1.1,
resize: float = 0.7,
fps: int = 10,
) -> Recording:
with create_temp_path() as temp_path:
log.info(f"Creating recording in {temp_path}")
html_path = temp_path / "termin.html"
html_path.write_text(self.html)
with sync_playwright() as p:
browser = p.chromium.launch()
dimensions = dict(width=800, height=530)
context = browser.new_context(
viewport=dimensions,
record_video_dir=str(temp_path.resolve()),
record_video_size=dimensions,
)
page = context.new_page()
page.goto(html_path.as_uri())
locators = PageLocators.from_page(page)
self.interactor(locators)
context.close()
browser.close()
for video in temp_path.glob("*.webm"):
return Recording.from_path(
path=video,
format=OutputFormat.WEBM,
).convert_to(
format,
Path(out_path),
begin_after=begin_after,
resize=resize,
fps=fps,
)
raise ValueError(f"No video found in temp_path {temp_path}")