Architecture

Technical overview of youtube-music-cli’s architecture.

Overview

youtube-music-cli is built with:

Project Structure

youtube-music-cli/
β”œβ”€β”€ source/
β”‚   β”œβ”€β”€ cli.tsx              # CLI entry point
β”‚   β”œβ”€β”€ app.tsx              # App setup
β”‚   β”œβ”€β”€ main.tsx             # Root component with providers
β”‚   β”‚
β”‚   β”œβ”€β”€ components/          # UI Components
β”‚   β”‚   β”œβ”€β”€ layouts/         # Main view layouts
β”‚   β”‚   β”œβ”€β”€ player/          # Player components
β”‚   β”‚   β”œβ”€β”€ search/          # Search components
β”‚   β”‚   β”œβ”€β”€ plugins/         # Plugin management UI
β”‚   β”‚   β”œβ”€β”€ settings/        # Settings UI
β”‚   β”‚   └── common/          # Shared components
β”‚   β”‚
β”‚   β”œβ”€β”€ services/            # Business logic
β”‚   β”‚   β”œβ”€β”€ player/          # Audio playback
β”‚   β”‚   β”œβ”€β”€ youtube-music/   # YouTube Music API
β”‚   β”‚   β”œβ”€β”€ plugin/          # Plugin system
β”‚   β”‚   β”œβ”€β”€ config/          # Configuration
β”‚   β”‚   └── logger/          # Logging
β”‚   β”‚
β”‚   β”œβ”€β”€ stores/              # State management
β”‚   β”‚   β”œβ”€β”€ player.store.tsx
β”‚   β”‚   β”œβ”€β”€ navigation.store.tsx
β”‚   β”‚   └── plugins.store.tsx
β”‚   β”‚
β”‚   β”œβ”€β”€ hooks/               # Custom React hooks
β”‚   β”œβ”€β”€ types/               # TypeScript definitions
β”‚   β”œβ”€β”€ contexts/            # React contexts
β”‚   └── utils/               # Utilities
β”‚
β”œβ”€β”€ plugins/                 # Plugin submodule
β”œβ”€β”€ templates/               # Plugin templates
β”œβ”€β”€ docs/                    # Documentation
└── dist/                    # Compiled output

State Management

Uses React Context + useReducer pattern:

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   Providers     β”‚
                    β”‚                 β”‚
                    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
                    β”‚ β”‚ThemeProviderβ”‚ β”‚
                    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
                    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
                    β”‚ β”‚PlayerProviderβ”‚ β”‚
                    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
                    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
                    β”‚ β”‚NavProvider  β”‚ β”‚
                    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
                    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
                    β”‚ β”‚PluginsProviderβ”‚ β”‚
                    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
                            β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   MainLayout    β”‚
                    β”‚   (Router)      β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Player Store

Manages playback state:

Manages view navigation:

Plugins Store

Manages plugin state:

Service Layer

Services encapsulate external dependencies:

PlayerService

Wraps mpv/yt-dlp for audio playback.

const player = getPlayerService();
await player.play(track);
player.pause();
player.setVolume(80);

MusicService

Wraps YouTube Music API (Innertube).

const music = getMusicService();
const results = await music.search('query');
const suggestions = await music.getSuggestions(videoId);

PluginRegistryService

Manages plugin lifecycle.

const registry = getPluginRegistryService();
await registry.loadAllPlugins();
await registry.enablePlugin('adblock');

Plugin System

Plugin Lifecycle

Install β†’ Load β†’ Init β†’ Enable β†’ (Running) β†’ Disable β†’ Destroy β†’ Uninstall

Plugin Context

Plugins receive a context object with APIs:

{
  player,      // Playback control
  navigation,  // View navigation
  config,      // Configuration storage
  logger,      // Logging
  filesystem,  // File operations
  audio,       // Audio stream hooks
  on/off/emit, // Event system
}

Event Flow

User Action β†’ Store Dispatch β†’ State Update β†’ Plugin Hook β†’ UI Re-render
                                    β”‚
                                    β–Ό
                            Plugin Event Emitted

Component Architecture

Layouts

Each view has a dedicated layout component:

Ink Primitives

Components use Ink’s Box and Text:

<Box flexDirection="column" padding={1}>
	<Text color="green">Now Playing</Text>
	<Text>{track.title}</Text>
</Box>

Data Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Input   │───▢│  Store   │───▢│   UI     β”‚
β”‚(Keyboard)β”‚    β”‚(Reducer) β”‚    β”‚(React)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
                     β–Ό
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚ Services β”‚
               β”‚(Side FX) β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Build Process

  1. TypeScript Compilation (tsc)
  2. Output to dist/
  3. Entry: dist/source/cli.js
bun run build  # Runs format β†’ lint β†’ typecheck β†’ tsc

Testing

bun run test