diff --git a/src/ytstudio/banner.py b/src/ytstudio/banner.py new file mode 100644 index 0000000..4827990 --- /dev/null +++ b/src/ytstudio/banner.py @@ -0,0 +1,41 @@ +from importlib.resources import files + +from rich.align import Align +from rich.console import Group, RenderableType +from rich.text import Text + +# Source-of-truth ASCII art sits next to this module as `banner.txt`. Edit the +# text file to tweak the art; no code change needed. +BANNER = (files("ytstudio") / "banner.txt").read_text().rstrip("\n") + +TAGLINE_LINES = ( + "Manage and analyze your YouTube channel from the terminal.", + "Designed for humans and AI agents.", +) + +# YouTube brand red; "f" cells form the outer ring, everything else is the +# play-button glyph in the centre. +_RED = "#ff0000" +_GLYPH = "bold white" + + +def _styled_banner() -> Text: + text = Text(no_wrap=True) + for ch in BANNER: + if ch in ("\n", " "): + text.append(ch) + elif ch == "f": + text.append(ch, style=_RED) + else: + text.append(ch, style=_GLYPH) + return text + + +def render_version_banner(version: str) -> RenderableType: + """Banner + tagline + version, centred for the --version screen.""" + parts: list[RenderableType] = [Align.center(_styled_banner()), Text("")] + for line in TAGLINE_LINES: + parts.append(Align.center(Text(line, style="bold"))) + parts.append(Text("")) + parts.append(Align.center(Text(f"v{version}", style="dim"))) + return Group(*parts) diff --git a/src/ytstudio/banner.txt b/src/ytstudio/banner.txt new file mode 100644 index 0000000..3ea9473 --- /dev/null +++ b/src/ytstudio/banner.txt @@ -0,0 +1,25 @@ + ffffffff + ffffffffffffff + ffffffffffffffffffff + ffffffffffffffffffffffffff + fffffffffffffffrXYxfffffffffffffff + ffffffffffffffrkMLjjLMkrffffffffffffff +ffffffffffffchMQFffffffFLMacffffffffffff +fffffffffvoWXFffffffffffffFXWocfffffffff +fffffffYMUffffffffffffffffffffJMXfffffff +fffffffoYffffffXMdFffffffffffffYofffffff +fffffffoYffffffXWWWWpnfffffffffYofffffff +fffffffoYffffffXWWWWWWWajffffffYofffffff +fffffffoYffffffXWWWWWWWWWWqffffYofffffff +fffffffoYffffffXWWWWWWWkFffffffYofffffff +fffffffoYffffffXWWWWqxfffffffffYofffffff +fffffffoYffffffXMqFffffffffffffYMfffffff +fffffffzMCffffffffffffffffffffCMzfffffff +fffffffffxaWUFffffffffffffFJWaxfffffffff +ffffffffffffnbMmjffffffjmMbuffffffffffff + ffffffffffffffjdMwrrwMbjffffffffffffff + fffffffffffffffrXzjfffffffffffffff + ffffffffffffffffffffffffff + ffffffffffffffffffff + ffffffffffffff + ffffffff diff --git a/src/ytstudio/main.py b/src/ytstudio/main.py index 57339a3..8f6b004 100644 --- a/src/ytstudio/main.py +++ b/src/ytstudio/main.py @@ -4,6 +4,7 @@ from rich.console import Console from ytstudio.api import authenticate, get_status +from ytstudio.banner import render_version_banner from ytstudio.commands import analytics, comments, livestreams, profile, videos from ytstudio.config import migrate_legacy_credentials, setup_credentials from ytstudio.version import get_current_version, is_update_available @@ -76,7 +77,7 @@ def main( ): """ytstudio - Manage your YouTube channel from the terminal""" if show_version: - console.print(f"ytstudio v{get_current_version()}") + console.print(render_version_banner(get_current_version())) raise typer.Exit() migrate_legacy_credentials() diff --git a/tests/test_banner.py b/tests/test_banner.py new file mode 100644 index 0000000..606e635 --- /dev/null +++ b/tests/test_banner.py @@ -0,0 +1,16 @@ +from typer.testing import CliRunner + +from ytstudio.main import app +from ytstudio.version import get_current_version + +runner = CliRunner() + + +def test_version_shows_banner_tagline_and_version(): + result = runner.invoke(app, ["--version"]) + + assert result.exit_code == 0 + assert "WWW" in result.stdout + assert "Manage and analyze your YouTube channel from the terminal." in result.stdout + assert "Designed for humans and AI agents." in result.stdout + assert f"v{get_current_version()}" in result.stdout