View on GitHub

PyKaraoke-NG

A free, open-source karaoke player for Linux, Windows, and macOS

PyKaraoke NG Architecture Documentation

← Back to Home Developer Guide

Migration from wxPython to Tauri

This document describes the architectural transformation of PyKaraoke from a monolithic wxPython application to a modern, decoupled Tauri-based architecture.

Problem Statement

The original PyKaraoke application was tightly coupled to wxPython:

Solution Architecture

High-Level Design

┌──────────────────────────────────────────────────────────────────┐
│                         Desktop Application                       │
│                                                                    │
│  ┌─────────────────┐           ┌──────────────────────────┐     │
│  │  Web Frontend   │           │   Tauri Shell (Rust)     │     │
│  │  (HTML/CSS/JS)  │◄─────────►│   • Window Management    │     │
│  │                 │   Events  │   • Native Integration   │     │
│  │  • UI Views     │           │   • IPC Router           │     │
│  │  • User Input   │           │   • Process Manager      │     │
│  └─────────────────┘           └──────────────────────────┘     │
│                                           │                       │
│                                           │ stdin/stdout          │
│                                           │ (JSON Protocol)       │
│                                           ▼                       │
│                          ┌─────────────────────────────┐         │
│                          │  Python Backend Service     │         │
│                          │  (pykbackend.py)            │         │
│                          │                             │         │
│                          │  ┌──────────────────────┐  │         │
│                          │  │  Command Processor   │  │         │
│                          │  └──────────────────────┘  │         │
│                          │            ▼                │         │
│                          │  ┌──────────────────────┐  │         │
│                          │  │  Core Engine         │  │         │
│                          │  │  (pykplayer,         │  │         │
│                          │  │   pykmanager, etc)   │  │         │
│                          │  └──────────────────────┘  │         │
│                          │            ▼                │         │
│                          │  ┌──────────────────────┐  │         │
│                          │  │  Database & Library  │  │         │
│                          │  │  (pykdb)             │  │         │
│                          │  └──────────────────────┘  │         │
│                          │            ▼                │         │
│                          │  ┌──────────────────────┐  │         │
│                          │  │  Players             │  │         │
│                          │  │  (pycdg, pykar,      │  │         │
│                          │  │   pympg)             │  │         │
│                          │  └──────────────────────┘  │         │
│                          └─────────────────────────────┘         │
└──────────────────────────────────────────────────────────────────┘

Component Responsibilities

1. Python Backend Service (pykbackend.py)

Purpose: Headless service managing all karaoke business logic

Responsibilities:

Key Features:

API Design:

2. Tauri Shell (Rust)

Purpose: Native desktop wrapper and IPC bridge

Responsibilities:

Key Components:

3. Web Frontend (HTML/CSS/JavaScript)

Purpose: User interface layer

Responsibilities:

UI Sections:

  1. Player Controls: Play/pause/stop, progress, volume
  2. Library Browser: Search, filter, browse songs
  3. Playlist Manager: Queue, reorder, remove songs
  4. Settings: Configure app behavior

Technology Choices:

Communication Protocol

Message Format

All messages are JSON objects sent over stdin/stdout.

Command (Frontend → Backend)

{
  "action": "string",       // Command name
  "params": {               // Optional parameters
    "key": "value"
  }
}

Response (Backend → Frontend)

{
  "type": "response",
  "response": {
    "status": "ok|error",   // Result status
    "message": "string",    // Optional message
    "data": {}              // Optional data payload
  }
}

Event (Backend → Frontend)

{
  "type": "event",
  "event": {
    "type": "event_name",
    "timestamp": 1234567890.123,
    "data": {}
  }
}

Command Reference

Action Parameters Description
play playlist_index? Start/resume playback
pause - Pause playback
stop - Stop and reset
next - Next track
previous - Previous track
seek position_ms Seek to position
set_volume volume (0-1) Adjust volume
load_song filepath Load a song file
add_to_playlist filepath Add to queue
remove_from_playlist index Remove from queue
clear_playlist - Empty playlist
search_songs query Search library
get_library - List all songs
scan_library - Rescan folders
add_folder folder Add library folder
get_state - Get current state
get_settings - Get app settings
update_settings settings Update settings

Event Reference

Event Type Data Description
state_changed Full state object State updated
song_finished - Track completed
playback_error error Error occurred
playlist_updated playlist Queue changed
library_scan_complete - Scan finished
volume_changed volume Volume adjusted

State Management

Backend State

The Python backend maintains authoritative state:

{
    "playback_state": "idle|playing|paused|stopped|loading|error",
    "current_song": {
        "title": str,
        "artist": str,
        "filename": str,
        "filepath": str,
        "zip_name": str?
    },
    "playlist": [SongStruct, ...],
    "playlist_index": int,
    "volume": float (0-1),
    "position_ms": int,
    "duration_ms": int,
    "error": str?
}

Frontend State

Frontend maintains local UI state:

The frontend regularly polls get_state to sync with backend.

Migration Strategy

Phase 1: Backend Extraction ✅

  1. Created pykbackend.py - headless backend service
  2. Extracted core logic from wx dependencies
  3. Implemented JSON command API
  4. Added event emission system

Phase 2: Tauri Setup ✅

  1. Created Tauri project structure
  2. Implemented Rust IPC handlers
  3. Created Python subprocess manager
  4. Configured message routing

Phase 3: Frontend Development ✅

  1. Built web UI (HTML/CSS/JS)
  2. Implemented player controls
  3. Created library browser
  4. Added playlist management

Phase 4: Integration (In Progress)

Phase 5: Testing & Polish

Benefits of New Architecture

  1. Separation of Concerns: UI and logic are decoupled
  2. Modern UI: Web technologies enable rich, responsive UI
  3. Testability: Components can be tested independently
  4. Cross-Platform: Tauri supports Windows, macOS, Linux
  5. Maintainability: Clear interfaces and boundaries
  6. Extensibility: Easy to add new features
  7. Performance: Rust runtime is lightweight and fast
  8. Distribution: Single binary with embedded assets

Development Workflow

Running the App

# Development mode
cd tauri-app
cargo tauri dev

# Production build
cargo tauri build

Testing Backend Standalone

# Run backend service
python3 pykbackend.py

# Send test commands (in another terminal)
echo '{"action":"get_state","params":{}}' | python3 pykbackend.py

Debugging

Future Enhancements

  1. WebSocket Support: Replace stdio with WebSocket for better performance
  2. HTTP API: Add REST API for remote control
  3. Plugin System: Allow extensions via plugins
  4. Cloud Sync: Sync playlists and settings
  5. Mobile App: Build companion mobile app
  6. Web Version: Deploy frontend as web app with backend as service

Backward Compatibility

Technical Decisions

Why Tauri?

Why stdio vs WebSocket?

Why JSON vs Protocol Buffers?

Conclusion

This architecture modernizes PyKaraoke while preserving its core functionality. The separation of UI and logic enables:

The migration is incremental and non-breaking, allowing gradual adoption.