Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/ytstudio/banner.py
Original file line number Diff line number Diff line change
@@ -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)
25 changes: 25 additions & 0 deletions src/ytstudio/banner.txt
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion src/ytstudio/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down
16 changes: 16 additions & 0 deletions tests/test_banner.py
Original file line number Diff line number Diff line change
@@ -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