From 66210a04b84812863e012409213c2cff8f0235dc Mon Sep 17 00:00:00 2001 From: blissfulboy Date: Fri, 13 Mar 2026 20:44:03 +0000 Subject: [PATCH] Refactor variable names for consistency and clarity Refactor variable names and improve readability in main.py. --- main.py | 150 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 90 insertions(+), 60 deletions(-) diff --git a/main.py b/main.py index c7fa434..225696d 100644 --- a/main.py +++ b/main.py @@ -6,75 +6,105 @@ import subprocess import numpy as np -BLOCK = '▀' +BLOCK = "▀" RESET = "\033[0m" def ClearConsole(): - time.sleep(0.1) - os.system('cls' if os.name == 'nt' else 'clear') + os.system("cls" if os.name == "nt" else "clear") -def RGB(R, G, B): - return f"\033[48;2;{R};{G};{B}m" - -def GetVideoCapture(Path): - Cap = cv2.VideoCapture(Path) - if not Cap.isOpened(): +def GetVideoCapture(path): + cap = cv2.VideoCapture(path) + if not cap.isOpened(): print("Error: Cannot open video.") sys.exit(1) - Fps = Cap.get(cv2.CAP_PROP_FPS) - return Cap, Fps - -def ResizeFrame(Frame, Width, Height): - Frame = cv2.cvtColor(Frame, cv2.COLOR_BGR2RGB) - return cv2.resize(Frame, (Width, Height * 2), interpolation=cv2.INTER_AREA) - -def FrameToAscii(FrameImg): - Height, Width, _ = FrameImg.shape - TopPixels = FrameImg[0::2] - BottomPixels = FrameImg[1::2] - if BottomPixels.shape[0] < TopPixels.shape[0]: - BottomPixels = np.vstack([BottomPixels, np.zeros((1, Width, 3), dtype=np.uint8)]) - Lines = [] - for TRow, BRow in zip(TopPixels, BottomPixels): - Line = ''.join([ - f"\033[48;2;{b[0]};{b[1]};{b[2]}m\033[38;2;{r[0]};{r[1]};{r[2]}m{BLOCK}" - for r, b in zip(TRow, BRow) - ]) + RESET - Lines.append(Line) - return Lines - -def PrintAsciiFrame(Lines): - FrameStr = "\033[H" + "\n".join(Lines) - sys.stdout.write(FrameStr) + fps = cap.get(cv2.CAP_PROP_FPS) or 0 + if fps <= 0: + fps = 30.0 + return cap, fps + +def ResizeFrame(frame, width, height): + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + return cv2.resize(frame, (width, height * 2), interpolation=cv2.INTER_AREA) + +def FrameToAscii(frame_img): + height, width, _ = frame_img.shape + top_pixels = frame_img[0::2] + bottom_pixels = frame_img[1::2] + if bottom_pixels.shape[0] < top_pixels.shape[0]: + bottom_pixels = np.vstack([bottom_pixels, np.zeros((1, width, 3), dtype=np.uint8)]) + + lines = [] + for top_row, bottom_row in zip(top_pixels, bottom_pixels): + line = "".join( + f"\033[48;2;{bottom_px[0]};{bottom_px[1]};{bottom_px[2]}m" + f"\033[38;2;{top_px[0]};{top_px[1]};{top_px[2]}m{BLOCK}" + for top_px, bottom_px in zip(top_row, bottom_row) + ) + RESET + lines.append(line) + return lines + +def PrintAsciiFrame(lines): + frame_str = "\033[H" + "\n".join(lines) + sys.stdout.write(frame_str) sys.stdout.flush() def GetTerminalSize(): - Size = shutil.get_terminal_size(fallback=(80, 24)) - return Size.columns, Size.lines - -def PlayVideoAscii(VideoPath): - TermWidth, TermHeight = GetTerminalSize() - Width = TermWidth - Height = TermHeight - Cap, Fps = GetVideoCapture(VideoPath) - FrameDuration = 1 / Fps - AudioProcess = subprocess.Popen(["ffplay", "-nodisp", "-autoexit", "-loglevel", "quiet", VideoPath]) - StartTime = time.time() - FrameNumber = 0 + size = shutil.get_terminal_size(fallback=(80, 24)) + # leave one row so we don't scroll the terminal + return size.columns, max(1, size.lines - 1) + +def PlayVideoAscii(video_path): + term_width, term_height = GetTerminalSize() + width = term_width + height = term_height + + cap, fps = GetVideoCapture(video_path) + frame_duration = 1 / fps + + audio_process = None + try: + audio_process = subprocess.Popen( + ["ffplay", "-nodisp", "-autoexit", "-loglevel", "quiet", video_path], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + except Exception: + audio_process = None + + start_time = time.time() + frame_number = 0 + while True: - Ret, Frame = Cap.read() - if not Ret: + # skip frames if we are behind to reduce drift + now = time.time() + target_frame = int((now - start_time) / frame_duration) + while frame_number < target_frame: + ret, _ = cap.read() + if not ret: + cap.release() + if audio_process: + audio_process.terminate() + ClearConsole() + return + frame_number += 1 + + ret, frame = cap.read() + if not ret: break - Resized = ResizeFrame(Frame, Width, Height) - AsciiLines = FrameToAscii(Resized) - PrintAsciiFrame(AsciiLines) - FrameNumber += 1 - TargetTime = StartTime + FrameNumber * FrameDuration - Now = time.time() - SleepTime = TargetTime - Now - if SleepTime > 0: - time.sleep(SleepTime) - Cap.release() + + resized = ResizeFrame(frame, width, height) + ascii_lines = FrameToAscii(resized) + PrintAsciiFrame(ascii_lines) + + frame_number += 1 + target_time = start_time + frame_number * frame_duration + sleep_time = target_time - time.time() + if sleep_time > 0: + time.sleep(sleep_time) + + cap.release() + if audio_process: + audio_process.terminate() ClearConsole() if __name__ == "__main__": @@ -82,8 +112,8 @@ def PlayVideoAscii(VideoPath): print("Usage: python script.py ") sys.exit(1) - VideoPath = sys.argv[1] + video_path = sys.argv[1] try: - PlayVideoAscii(VideoPath) + PlayVideoAscii(video_path) except KeyboardInterrupt: ClearConsole()