home / skills / dbobkov245-source / pwa-torserve / capacitor-bridge

capacitor-bridge skill

/skills/capacitor-bridge

This skill orchestrates React and Android native bridge to launch external video players, resuming playback position after completion.

npx playbooks add skill dbobkov245-source/pwa-torserve --skill capacitor-bridge

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
2.8 KB
---
name: capacitor-bridge
description: Specialist in Android Intents, Java-JS bridging, and External Player integration.
---

# Capacitor Bridge Skill

This skill handles the communication between the React Frontend and the Native Android layer (`TVPlayer.java`).
**Primary Goal:** Launch external players (VLC, MX Player, Vimu) correctly and handle their return results (resume position).

## 桥 API Contract

### `TVPlayer.play(options)`
Launches a single video file. **Must return a Promise that resolves only after the player closes.**

**Options:**
*   `url` (string, required): Direct link to the video stream.
*   `package` (string, optional): Specific player package name (e.g., `net.gtvbox.videoplayer`). If null, opens system chooser.
*   `title` (string): Title to display in the player.
*   `position` (number): Resume position in milliseconds.

**Java Extras (What actually gets sent):**
*   `Intent.ACTION_VIEW`
*   `return_result`: `true`
*   **Flags:** `FLAG_ACTIVITY_CLEAR_TOP`, `FLAG_ACTIVITY_SINGLE_TOP` (Crucial for preventing double rendering).

### `TVPlayer.playList(options)`
Launches a playlist (Season/Series).

**Options:**
*   `urls` (string[]): Array of video URLs.
*   `names` (string[]): Array of episode titles.
*   `startIndex` (number): Which index to start playing.
*   `position` (number): Resume position for the *started* episode.

## 📱 Supported Players & Extras

### Vimu Player (`net.gtvbox.videoplayer`)
*   **Single:** `forcename` (Title), `forcedirect` (No buffer), `startfrom` (Position).
*   **Playlist:** Uses `application/vnd.gtvbox.filelist` MIME type.
    *   `asusfilelist` (URLs)
    *   `asusnamelist` (Names)

### MX Player (`com.mxtech.videoplayer.ad` / `.pro`)
*   **Single:** `title`, `position`.
*   **Playlist:** Uses standard `video/*` with extras.
    *   `video_list` (Parcelable Uri[])
    *   `video_list.name` (String[])

### VLC (`org.videolan.vlc`)
*   **Single:** `title`, `from_start` (false).
*   **Playlist:** *Not fully supported via Intent extras, falls back to acting as single file player currently.*

## ⚠️ Critical Rules
1.  **Do NOT change `FLAG_ACTIVITY_SINGLE_TOP`.** This prevents the app from restarting or opening a second instance of the intent chooser.
2.  **RESTRICTED: `FLAG_ACTIVITY_NEW_TASK` and `FLAG_ACTIVITY_CLEAR_TOP`**. These flags are essential for correct stack manipulation between PWA and Native Player. Removing them breaks the return journey.
3.  **Lifecycle:** The promise resolves when `onActivityResult` fires (i.e., user closes the player).
    *   **Requirement:** `play()` method MUST return a Promise resolving with `{ position, duration }`.
4.  **Resume Logic:** The result object contains `{ position: number, duration: number, finished: boolean }`. You MUST save this to `localStorage` immediately.

Overview

This skill handles the bridge between a React frontend and the native Android player layer to launch external players and manage their return results. It focuses on reliable Intent construction, player-specific extras, and guaranteeing the play() Promise resolves only after the external player closes. The skill ensures resume position and duration are captured and persisted for seamless playback recovery.

How this skill works

It exposes play() and playList() operations that construct Android Intents with required flags and extras, then waits for onActivityResult to resolve a Promise with { position, duration, finished }. The implementation applies player-specific extras (Vimu, MX Player, VLC), enforces critical Intent flags, and writes the returned resume data to localStorage immediately. The bridge supports single files and playlists, mapping arrays and names into the correct MIME type and extras per player.

When to use it

  • Launching an external Android video player from a React webview/PWA and needing a resume result.
  • Starting a playlist (season/series) in a native player while preserving episode names and start index.
  • Integrating Vimu, MX Player, or VLC with player-specific extras and resume handling.
  • Ensuring the app returns to the PWA with correct playback position and duration after external playback.

Best practices

  • Always return a Promise from play() that resolves only when onActivityResult fires with the result object.
  • Never remove FLAG_ACTIVITY_SINGLE_TOP; keep FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP to avoid duplicate instances.
  • Persist the returned { position, duration, finished } to localStorage immediately on resolution.
  • Prefer player-specific extras when targeting Vimu or MX Player to enable playlist and resume features.
  • Avoid using FLAG_ACTIVITY_NEW_TASK unless you fully understand stack implications between PWA and native players.

Example use cases

  • Play a single streamed file in Vimu with forcename and startfrom to resume at a saved position.
  • Start a season playlist in MX Player using video_list and video_list.name arrays with a startIndex.
  • Open VLC for one-off playback when playlist support is not required, and capture resume on close.
  • Launch system chooser by omitting package to let the user pick an installed player and still receive onActivityResult.

FAQ

What must play() return?

play() must return a Promise that resolves with { position, duration, finished } after the external player closes (onActivityResult).

Which Intent flags are mandatory?

Keep FLAG_ACTIVITY_SINGLE_TOP and FLAG_ACTIVITY_CLEAR_TOP. Removing them breaks return behavior and can cause duplicate rendering.

How should resume data be stored?

Immediately save the returned resume object to localStorage to ensure position/duration persistence across sessions.