From a7883e3439e7b553de023c99ab65328766ae932f Mon Sep 17 00:00:00 2001 From: WyattBlue Date: Wed, 18 Sep 2024 03:08:53 -0400 Subject: [PATCH] Remember old progress bar when starting new one --- auto_editor/edit.py | 4 +- auto_editor/ffwrapper.py | 2 +- auto_editor/output.py | 8 +-- auto_editor/preview.py | 4 +- auto_editor/subcommands/levels.py | 4 +- auto_editor/subcommands/repl.py | 5 +- auto_editor/utils/bar.py | 105 ++++++++++++++++-------------- 7 files changed, 69 insertions(+), 63 deletions(-) diff --git a/auto_editor/edit.py b/auto_editor/edit.py index da4987a07..b3acfa32a 100644 --- a/auto_editor/edit.py +++ b/auto_editor/edit.py @@ -11,7 +11,7 @@ from auto_editor.render.subtitle import make_new_subtitles from auto_editor.render.video import render_av from auto_editor.timeline import v1, v3 -from auto_editor.utils.bar import Bar +from auto_editor.utils.bar import initBar from auto_editor.utils.chunks import Chunk, Chunks from auto_editor.utils.cmdkw import ParserError, parse_with_palet, pAttr, pAttrs from auto_editor.utils.container import Container, container_constructor @@ -146,7 +146,7 @@ def parse_export(export: str, log: Log) -> dict[str, Any]: def edit_media(paths: list[str], ffmpeg: FFmpeg, args: Args, log: Log) -> None: - bar = Bar(args.progress) + bar = initBar(args.progress) tl = None if paths: diff --git a/auto_editor/ffwrapper.py b/auto_editor/ffwrapper.py index 7ec8f856f..e76dc64d2 100644 --- a/auto_editor/ffwrapper.py +++ b/auto_editor/ffwrapper.py @@ -294,7 +294,7 @@ def initFileInfo(path: str, log: Log) -> FileInfo: desc = cont.metadata.get("description", None) bitrate = 0 if cont.bit_rate is None else cont.bit_rate - dur = 0 if cont.duration is None else cont.duration / 1_000_000 + dur = 0 if cont.duration is None else cont.duration / av.time_base cont.close() diff --git a/auto_editor/output.py b/auto_editor/output.py index a5efb47c9..806072f5d 100644 --- a/auto_editor/output.py +++ b/auto_editor/output.py @@ -46,9 +46,9 @@ def audio(self, src: FileInfo, stream: int) -> str: astream = in_container.streams.audio[stream] if astream.duration is None or astream.time_base is None: - dur = 1 + dur = 1.0 else: - dur = int(astream.duration * astream.time_base) + dur = float(astream.duration * astream.time_base) bar.start(dur, "Extracting audio") @@ -58,8 +58,8 @@ def audio(self, src: FileInfo, stream: int) -> str: resampler = AudioResampler(format="s16", layout="stereo", rate=sample_rate) for i, frame in enumerate(in_container.decode(astream)): - if i % 1500 == 0: - bar.tick(0 if frame.time is None else frame.time) + if i % 1500 == 0 and frame.time is not None: + bar.tick(frame.time) for new_frame in resampler.resample(frame): for packet in output_astream.encode(new_frame): diff --git a/auto_editor/preview.py b/auto_editor/preview.py index 3fee70235..acdda610d 100644 --- a/auto_editor/preview.py +++ b/auto_editor/preview.py @@ -7,7 +7,7 @@ from auto_editor.analyze import Levels from auto_editor.timeline import v3 -from auto_editor.utils.bar import Bar +from auto_editor.utils.bar import initBar from auto_editor.utils.func import to_timecode from auto_editor.utils.log import Log @@ -65,7 +65,7 @@ def preview(tl: v3, log: Log) -> None: in_len = 0 for src in all_sources: - in_len += Levels(src, tb, Bar("none"), False, log, False).media_length + in_len += Levels(src, tb, initBar("none"), False, log, False).media_length out_len = tl.out_len() diff --git a/auto_editor/subcommands/levels.py b/auto_editor/subcommands/levels.py index 68f252405..17e28f424 100644 --- a/auto_editor/subcommands/levels.py +++ b/auto_editor/subcommands/levels.py @@ -11,7 +11,7 @@ from auto_editor.ffwrapper import initFileInfo from auto_editor.lang.palet import env from auto_editor.lib.contracts import is_bool, is_nat, is_nat1, is_str, is_void, orc -from auto_editor.utils.bar import Bar +from auto_editor.utils.bar import initBar from auto_editor.utils.cmdkw import ( ParserError, Required, @@ -83,7 +83,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None: parser = levels_options(ArgumentParser("levels")) args = parser.parse_args(LevelArgs, sys_args) - bar = Bar("none") + bar = initBar("none") log = Log(quiet=True) sources = [initFileInfo(path, log) for path in args.input] diff --git a/auto_editor/subcommands/repl.py b/auto_editor/subcommands/repl.py index 6ab8f94e0..93227e167 100644 --- a/auto_editor/subcommands/repl.py +++ b/auto_editor/subcommands/repl.py @@ -11,7 +11,7 @@ from auto_editor.lang.stdenv import make_standard_env from auto_editor.lib.data_structs import print_str from auto_editor.lib.err import MyError -from auto_editor.utils.bar import Bar +from auto_editor.utils.bar import initBar from auto_editor.utils.log import Log from auto_editor.utils.types import frame_rate from auto_editor.vanparse import ArgumentParser @@ -64,9 +64,8 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None: sources = [initFileInfo(path, log) for path in args.input] src = sources[0] tb = src.get_fps() if args.timebase is None else args.timebase - bar = Bar("modern") env["timebase"] = tb - env["@levels"] = Levels(src, tb, bar, False, log, strict) + env["@levels"] = Levels(src, tb, initBar("modern"), False, log, strict) env.update(make_standard_env()) print(f"Auto-Editor {auto_editor.__version__}") diff --git a/auto_editor/utils/bar.py b/auto_editor/utils/bar.py index 8032a4594..898a9245d 100644 --- a/auto_editor/utils/bar.py +++ b/auto_editor/utils/bar.py @@ -1,6 +1,7 @@ from __future__ import annotations import sys +from dataclasses import dataclass from math import floor from shutil import get_terminal_size from time import localtime, time @@ -8,39 +9,50 @@ from .func import get_stdout_bytes -class Bar: - def __init__(self, bar_type: str) -> None: - self.machine = False - self.hide = False +def initBar(bar_type: str) -> Bar: + icon = "⏳" + chars: tuple[str, ...] = (" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█") + brackets = ("|", "|") + machine = hide = False + + if bar_type == "classic": + icon = "⏳" + chars = ("░", "█") + brackets = ("[", "]") + if bar_type == "ascii": + icon = "& " + chars = ("-", "#") + brackets = ("[", "]") + if bar_type == "machine": + machine = True + if bar_type == "none": + hide = True + + part_width = len(chars) - 1 + + ampm = True + if sys.platform == "darwin" and bar_type in ("modern", "classic", "ascii"): + try: + date_format = get_stdout_bytes( + ["defaults", "read", "com.apple.menuextra.clock", "Show24Hour"] + ) + ampm = date_format == b"0\n" + except FileNotFoundError: + pass - self.icon = "⏳" - self.chars: tuple[str, ...] = (" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█") - self.brackets = ("|", "|") + return Bar(icon, chars, brackets, machine, hide, part_width, ampm, []) - if bar_type == "classic": - self.icon = "⏳" - self.chars = ("░", "█") - self.brackets = ("[", "]") - if bar_type == "ascii": - self.icon = "& " - self.chars = ("-", "#") - self.brackets = ("[", "]") - if bar_type == "machine": - self.machine = True - if bar_type == "none": - self.hide = True - - self.part_width = len(self.chars) - 1 - - self.ampm = True - if sys.platform == "darwin" and bar_type in ("modern", "classic", "ascii"): - try: - date_format = get_stdout_bytes( - ["defaults", "read", "com.apple.menuextra.clock", "Show24Hour"] - ) - self.ampm = date_format == b"0\n" - except FileNotFoundError: - pass + +@dataclass(slots=True) +class Bar: + icon: str + chars: tuple[str, ...] + brackets: tuple[str, str] + machine: bool + hide: bool + part_width: int + ampm: bool + stack: list[tuple[str, int, float, float]] @staticmethod def pretty_time(my_time: float, ampm: bool) -> str: @@ -62,28 +74,25 @@ def tick(self, index: float) -> None: if self.hide: return - progress = 0.0 if self.total == 0 else min(1, max(0, index / self.total)) - rate = 0.0 if progress == 0 else (time() - self.begin_time) / progress + title, len_title, total, begin = self.stack[-1] + progress = 0.0 if total == 0 else min(1, max(0, index / total)) + rate = 0.0 if progress == 0 else (time() - begin) / progress if self.machine: - index = min(index, self.total) - secs_til_eta = round(self.begin_time + rate - time(), 2) - print( - f"{self.title}~{index}~{self.total}~{secs_til_eta}", - end="\r", - flush=True, - ) + index = min(index, total) + secs_til_eta = round(begin + rate - time(), 2) + print(f"{title}~{index}~{total}~{secs_til_eta}", end="\r", flush=True) return - new_time = self.pretty_time(self.begin_time + rate, self.ampm) + new_time = self.pretty_time(begin + rate, self.ampm) percent = round(progress * 100, 1) p_pad = " " * (4 - len(str(percent))) columns = get_terminal_size().columns - bar_len = max(1, columns - (self.len_title + 32)) + bar_len = max(1, columns - (len_title + 32)) bar_str = self._bar_str(progress, bar_len) - bar = f" {self.icon}{self.title} {bar_str} {p_pad}{percent}% ETA {new_time}" + bar = f" {self.icon}{title} {bar_str} {p_pad}{percent}% ETA {new_time}" if len(bar) > columns - 2: bar = bar[: columns - 2] @@ -93,10 +102,7 @@ def tick(self, index: float) -> None: sys.stdout.write(bar + "\r") def start(self, total: float, title: str = "Please wait") -> None: - self.title = title - self.len_title = len(title) - self.total = total - self.begin_time = time() + self.stack.append((title, len(title), total, time())) try: self.tick(0) @@ -124,6 +130,7 @@ def _bar_str(self, progress: float, width: int) -> str: ) return line - @staticmethod - def end() -> None: + def end(self) -> None: sys.stdout.write(" " * (get_terminal_size().columns - 2) + "\r") + if self.stack: + self.stack.pop()