""" Preset pack encoder with ASCII art compression. Compresses plugin code and encodes it as ASCII art for fun and version control. """ import base64 import zlib import textwrap from typing import Tuple class PresetPackEncoder: """Encodes and decodes preset packs with ASCII art compression.""" # ASCII art frame characters FRAME_TOP_LEFT = "┌" FRAME_TOP_RIGHT = "┐" FRAME_BOTTOM_LEFT = "└" FRAME_BOTTOM_RIGHT = "┘" FRAME_HORIZONTAL = "─" FRAME_VERTICAL = "│" # Data block characters (for visual representation) DATA_CHARS = " ░▒▓█" @classmethod def encode_plugin_code(cls, code: str, name: str = "plugin") -> str: """Encode plugin code as ASCII art. Args: code: Python source code to encode name: Plugin name for metadata Returns: ASCII art encoded plugin code """ # Compress the code compressed = zlib.compress(code.encode("utf-8")) # Encode as base64 b64 = base64.b64encode(compressed).decode("ascii") # Wrap in ASCII art frame return cls._wrap_in_ascii_art(b64, name) @classmethod def decode_plugin_code(cls, ascii_art: str) -> str: """Decode ASCII art to plugin code. Args: ascii_art: ASCII art encoded plugin code Returns: Decoded Python source code """ # Extract base64 from ASCII art b64 = cls._extract_from_ascii_art(ascii_art) # Decode base64 compressed = base64.b64decode(b64) # Decompress code = zlib.decompress(compressed).decode("utf-8") return code @classmethod def _wrap_in_ascii_art(cls, data: str, name: str) -> str: """Wrap data in ASCII art frame.""" # Calculate frame width max_line_length = 60 lines = textwrap.wrap(data, max_line_length) # Find longest line for frame width longest_line = max(len(line) for line in lines) if lines else 0 frame_width = longest_line + 4 # 2 padding + 2 borders # Build ASCII art result = [] # Top border result.append( cls.FRAME_TOP_LEFT + cls.FRAME_HORIZONTAL * (frame_width - 2) + cls.FRAME_TOP_RIGHT ) # Plugin name header name_line = f" {name} " name_padding = frame_width - 2 - len(name_line) left_pad = name_padding // 2 right_pad = name_padding - left_pad result.append( cls.FRAME_VERTICAL + " " * left_pad + name_line + " " * right_pad + cls.FRAME_VERTICAL ) # Separator line result.append( cls.FRAME_VERTICAL + cls.FRAME_HORIZONTAL * (frame_width - 2) + cls.FRAME_VERTICAL ) # Data lines for line in lines: padding = frame_width - 2 - len(line) result.append( cls.FRAME_VERTICAL + line + " " * padding + cls.FRAME_VERTICAL ) # Bottom border result.append( cls.FRAME_BOTTOM_LEFT + cls.FRAME_HORIZONTAL * (frame_width - 2) + cls.FRAME_BOTTOM_RIGHT ) return "\n".join(result) @classmethod def _extract_from_ascii_art(cls, ascii_art: str) -> str: """Extract base64 data from ASCII art frame.""" lines = ascii_art.strip().split("\n") # Skip top and bottom borders, header, and separator data_lines = lines[3:-1] # Extract data from between frame characters extracted = [] for line in data_lines: if len(line) > 2: # Remove frame characters and extract content content = line[1:-1].rstrip() extracted.append(content) return "".join(extracted) @classmethod def encode_toml(cls, toml_data: str, name: str = "pack") -> str: """Encode TOML data as ASCII art. Args: toml_data: TOML configuration data name: Pack name Returns: ASCII art encoded TOML """ # Compress compressed = zlib.compress(toml_data.encode("utf-8")) # Encode as base64 b64 = base64.b64encode(compressed).decode("ascii") # Create visual representation using data characters visual_data = cls._data_to_visual(b64) return cls._wrap_in_ascii_art(visual_data, name) @classmethod def decode_toml(cls, ascii_art: str) -> str: """Decode ASCII art to TOML data. Args: ascii_art: ASCII art encoded TOML Returns: Decoded TOML data """ # Extract base64 from ASCII art b64 = cls._extract_from_ascii_art(ascii_art) # Decode base64 compressed = base64.b64decode(b64) # Decompress toml_data = zlib.decompress(compressed).decode("utf-8") return toml_data @classmethod def _data_to_visual(cls, data: str) -> str: """Convert base64 data to visual representation. This creates a fun visual pattern based on the data. """ # Simple mapping: each character to a data block character # This is purely for visual appeal visual = "" for i, char in enumerate(data): # Use character code to select visual block idx = ord(char) % len(cls.DATA_CHARS) visual += cls.DATA_CHARS[idx] # Add line breaks for visual appeal if (i + 1) % 60 == 0: visual += "\n" return visual @classmethod def get_visual_representation(cls, data: str) -> str: """Get a visual representation of data for display.""" compressed = zlib.compress(data.encode("utf-8")) b64 = base64.b64encode(compressed).decode("ascii") return cls._data_to_visual(b64)