# SmartTube Architecture Explained: Modular MVP Design for Android TV

> Explore the SmartTube architecture: a modular MVP design for Android TV. Learn how its distinct Gradle modules and Leanback integration create a robust, scalable application.

- Repository: [Yuriy L/SmartTube](https://github.com/yuliskov/SmartTube)
- Tags: architecture
- Published: 2026-09-14

---

**SmartTube implements a modular MVP (Model-View-Presenter) architecture built on Android Leanback and ExoPlayer, separating concerns across distinct Gradle modules including smarttubetv, common, and exoplayer-amzn.**

SmartTube is an open-source Android TV client that streams public YouTube content without requiring Google services. The yuliskov/SmartTube repository demonstrates a clean SmartTube architecture that isolates UI, business logic, and platform-specific playback concerns. This design makes it straightforward to extend individual components such as swapping ExoPlayer versions or adding new Leanback sections.

## Modular Project Structure

The codebase organizes functionality across several Gradle modules, each handling a distinct concern according to the SmartTube architecture:

- **smarttubetv** – Core TV application containing UI components, Leanback navigation, and playback logic
- **common** – Shared utilities including network helpers, update URLs, and application constants  
- **leanbackassistant** – Helper fragments and resources specific to the Leanback UI framework
- **exoplayer‑amzn‑2.10.6** – Customized ExoPlayer fork optimized for Amazon Fire TV devices
- **filepicker‑lib**, **doubletapplayerview**, **chatkit** – Optional UI widgets for file selection, gesture controls, and live chat functionality

## Application Entry Point

`MainApplication` serves as the global initialization point in [`smarttubetv/src/main/java/com/liskovsoft/smartyoutubetv2/tv/ui/main/MainApplication.java`](https://github.com/yuliskov/SmartTube/blob/main/smarttubetv/src/main/java/com/liskovsoft/smartyoutubetv2/tv/ui/main/MainApplication.java). This class configures application-wide services before any activity launches.

```java
// MainApplication.java
public class MainApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // Initialise logging, check for updates, configure Glide caching
        GlideCachingModule.register(this);
        Updater.checkForUpdates(this);
    }
}

```

The application registers a **Glide** caching module for image loading and triggers the built-in updater to check for new releases.

## Leanback Navigation Layer

The UI layer relies on Android's Leanback library, with entry points defined in launcher activities. `HomeLauncherActivity` extends `AppCompatActivity` and hosts the primary browse interface.

```java
// HomeLauncherActivity.java
public class HomeLauncherActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Attach BrowseFragment as the primary fragment
        getFragmentManager().beginTransaction()
            .replace(android.R.id.content, new BrowseFragment())
            .commit();
    }
}

```

The `BrowseFragment` class located in [`smarttubetv/src/main/java/com/liskovsoft/smartyoutubetv2/tv/ui/browse/BrowseFragment.java`](https://github.com/yuliskov/SmartTube/blob/main/smarttubetv/src/main/java/com/liskovsoft/smartyoutubetv2/tv/ui/browse/BrowseFragment.java) constructs the main content rows using a factory pattern.

```java
// BrowseFragment.java
public class BrowseFragment extends BrowseSupportFragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Create sections through the factory
        BrowseSectionFragmentFactory factory = new BrowseSectionFragmentFactory(getContext());
        setRows(factory.createRows());
    }
}

```

## Presenter Pattern Implementation

Presenters bridge the gap between YouTube data and Leanback adapters. `VideoCardPresenter` in [`smarttubetv/src/main/java/com/liskovsoft/smartyoutubetv2/tv/presenter/VideoCardPresenter.java`](https://github.com/yuliskov/SmartTube/blob/main/smarttubetv/src/main/java/com/liskovsoft/smartyoutubetv2/tv/presenter/VideoCardPresenter.java) handles the creation and binding of video card views.

```java
// VideoCardPresenter.java
public class VideoCardPresenter extends Presenter {
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent) {
        // Inflate card layout and bind click listeners
        View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.lb_image_card_view, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, Object item) {
        VideoInfo video = (VideoInfo) item;
        // Load thumbnail with Glide, attach actions
        Glide.with(viewHolder.view)
            .load(video.getThumbnailUrl())
            .into(((ImageView) viewHolder.view.findViewById(R.id.main_image)));
    }
}

```

This **Presenter** layer retrieves data via the YouTube API client, applies transformations such as SponsorBlock filtering and video-quality selection, and feeds the results to Leanback adapters.

## Playback Engine and ExoPlayer Integration

`PlaybackActivity` owns the player lifecycle and creates ExoPlayer instances via `ExoPlayerFactory`. The activity hosts `PlaybackFragment`, which provides Leanback transport controls.

```java
// PlaybackActivity.java
public class PlaybackActivity extends AppCompatActivity {
    private SimpleExoPlayer player;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        player = ExoPlayerFactory.newSimpleInstance(this);
        // Attach the fragment that shows transport controls
        getSupportFragmentManager().beginTransaction()
            .replace(android.R.id.content, new PlaybackFragment())
            .commit();
    }
}

```

Playback actions such as speed changes, HDR toggles, and SponsorBlock skips are implemented as discrete classes extending `TwoStateAction`. The speed control implementation in [`VideoSpeedAction.java`](https://github.com/yuliskov/SmartTube/blob/main/VideoSpeedAction.java) demonstrates this pattern:

```java
// VideoSpeedAction.java
public class VideoSpeedAction extends TwoStateAction {
    @Override
    public void onClicked() {
        float newSpeed = player.getPlaybackParameters().speed == 1f ? 1.5f : 1f;
        player.setPlaybackParameters(new PlaybackParameters(newSpeed));
    }
}

```

## SponsorBlock Integration

SponsorBlock functionality is accessed through `SponsorBlockClient`, a lightweight HTTP client that fetches segment data from the SponsorBlock API and injects skip logic into the player. The client retrieves segment boundaries for specific video IDs and schedules automatic skips when playback reaches designated start times.

```java
// SponsorBlockClient.java (simplified)
public class SponsorBlockClient {
    public List<SponsorSegment> fetchSegments(String videoId) {
        // GET https://sponsor.ajay.app/api/skipSegments?videoID=...
        // Parse JSON → List<SponsorSegment>
    }
}

```

The `VideoInfoAction` class checks for available segments and coordinates with the player to bypass sponsored content.

## Auxiliary Modules

The SmartTube architecture includes specialized modules that extend core functionality without cluttering the main codebase:

| Module | Example Class | Purpose |
|--------|---------------|---------|
| **exoplayer‑amzn‑2.10.6** | `ExoPlayerFactory` | Provides ExoPlayer builds tuned for Amazon Fire TV hardware |
| **filepicker‑lib** | `FilePickerActivity` | UI for selecting local APKs or media files |
| **doubletapplayerview** | `DoubleTapPlayView` | Handles double-tap gestures for quick forward/rewind |
| **chatkit** | `ChatFragment` | Optional live-chat UI for streams using WebSocket connections |

## Summary

- SmartTube uses a **modular MVP architecture** that separates UI (Leanback), business logic (Presenters), and playback (ExoPlayer) into distinct Gradle modules.
- The **smarttubetv** module contains the core application, while **exoplayer‑amzn** provides device-specific optimizations for Amazon hardware.
- **Presenter classes** like `VideoCardPresenter` adapt YouTube API data for Leanback adapters, enabling consistent UI patterns across the application.
- Playback features including **SponsorBlock**, variable speed, and HDR are implemented as discrete **Action classes** that interact with the ExoPlayer instance.
- The architecture allows developers to replace or extend individual layers—such as swapping ExoPlayer versions or adding new browse sections—without affecting the entire codebase.

## Frequently Asked Questions

### What architectural pattern does SmartTube use?

SmartTube implements a **Model-View-Presenter (MVP)** pattern combined with modular Gradle architecture. The UI layer uses Android Leanback fragments (View), the Presenter layer handles data fetching and transformation, and the Model layer consists of API clients and data repositories. This separation allows the `smarttubetv` module to focus purely on UI while business logic resides in presenter classes like `VideoCardPresenter`.

### How does SmartTube handle video playback without Google services?

The application uses **ExoPlayer** as its playback engine, instantiated via `ExoPlayerFactory` within `PlaybackActivity`. The player streams public YouTube content through the YouTube API client rather than the official YouTube SDK, eliminating the requirement for Google Play Services. The `exoplayer‑amzn` module provides Amazon-specific optimizations for Fire TV devices.

### How is SponsorBlock integrated into the playback flow?

SponsorBlock operates through a dedicated client class that queries the SponsorBlock API for segment data. When `PlaybackActivity` initializes a video, the system fetches sponsor segments and registers listeners on the ExoPlayer instance. When playback reaches a segment start time, the player automatically seeks to the end of the segment, skipping the sponsored content without user intervention.

### What is the purpose of the separate exoplayer-amzn module?

The **exoplayer‑amzn‑2.10.6** module maintains a customized fork of ExoPlayer specifically tuned for Amazon Fire TV hardware. This isolation allows the main `smarttubetv` module to remain device-agnostic while providing optimized decoder selection, DRM handling, and rendering pipelines for Amazon's specific Android implementation. Developers can update or replace this module independently without modifying the core application logic.