Jarian Cottingham 06877fb2fc feat: add TUI (Textual User Interface) with download queue system
- New TUI using Textual framework with responsive interface
- Search, results, download, and queue screens for YouTube video management
- Download queue system with sequential background downloads
- Status bar with queue count and download progress indicators
- Comprehensive test suite (97 tests) with 100% pass rate
- Modern Python packaging with pyproject.toml and uv support
- Added requirements-tui.txt for TUI-specific dependencies
- Updated setup.py and install.sh for TUI integration
- Enhanced README.md with TUI usage documentation
2026-02-25 15:59:15 -06:00

120 lines
3.7 KiB
Python

"""
Status Bar Widget for YouTube TUI
Simple status bar widget (custom footer handles queue status)
"""
from datetime import datetime
from textual.app import App
from textual.widgets import Static
class StatusBar(Static):
"""Simple status bar widget for YouTube TUI"""
def __init__(self, app: App, *args, **kwargs):
super().__init__(*args, **kwargs)
# Store app as _app since app is a read-only property in Static
self._app = app
self.current_screen = "Search"
self.status_message = "Ready"
self.downloading = False
self.queue_pending = 0
self.download_progress = 0
self.yt_dlp_version = "unknown"
self.update_version()
# Note: set_interval requires active app context, so we skip it in tests
# The timer functionality is tested separately if needed
try:
self.set_interval(1, self.update_time)
except Exception:
# Timer not available in test context, skip
pass
def update_version(self) -> None:
"""Update yt-dlp version"""
try:
import subprocess
result = subprocess.run(
["yt-dlp", "--version"],
capture_output=True,
text=True,
timeout=5,
)
if result.returncode == 0:
self.yt_dlp_version = result.stdout.strip()
else:
self.yt_dlp_version = "not installed"
except Exception:
self.yt_dlp_version = "unknown"
def set_screen(self, screen_name: str) -> None:
"""Set the current screen name"""
self.current_screen = screen_name
self.refresh()
def set_status(self, message: str) -> None:
"""Set status message"""
self.status_message = message
self.refresh()
def set_downloading(self, downloading: bool) -> None:
"""Set downloading state"""
self.downloading = downloading
self.refresh()
def set_queue_pending(self, count: int) -> None:
"""Set the number of pending queue items"""
self.queue_pending = count
self.refresh()
def set_download_progress(self, progress: int) -> None:
"""Set the current download progress percentage"""
self.download_progress = max(0, min(100, progress))
self.refresh()
def update_time(self) -> None:
"""Update the time display"""
self.refresh()
def render(self):
"""Render the status bar content"""
# Get current time
current_time = datetime.now().strftime("%H:%M:%S")
# Get theme info
theme_name = getattr(self._app, "theme", "css")
# Build status string
status_parts = [
f"[bold]{self.current_screen}[/bold]",
f"v{getattr(self._app, 'VERSION', '0.1.0')}",
f"yt-dlp {self.yt_dlp_version}",
]
# Add download indicator if downloading
if self.downloading:
status_parts.append("[bold green]↓[/bold green]")
# Add queue status if there are pending items
if self.queue_pending > 0:
status_parts.append(
f"[bold cyan]Queue: {self.queue_pending} pending[/bold cyan]"
)
# Add download progress if downloading
if self.downloading and self.download_progress > 0:
status_parts.append(
f"[bold yellow]Downloading: {self.download_progress}%[/bold yellow]"
)
# Add status message
status_parts.append(f"[bold]{self.status_message}[/bold]")
# Add footer elements
status_parts.append(f"[dim]{current_time}[/dim]")
status_parts.append(f"[dim]{theme_name} theme[/dim]")
return " ".join(status_parts)