# StreamVault — Stremio-Compatible Media Center for Android

## Project Overview

Build a full-featured, production-ready Android media center app called **StreamVault** that is fully compatible with the Stremio addon ecosystem. The app must be able to install and use any existing Stremio addon, browse catalogs, display metadata, resolve streams, and play video content — all with a modern, polished UI that improves on Stremio's Android experience.

This is a **publishable product** intended for distribution on the Google Play Store and as a direct APK download. It must be professional, stable, and performant.

---

## Tech Stack

| Layer | Technology |
|-------|-----------|
| Framework | React Native (latest stable) with TypeScript |
| Navigation | React Navigation v6+ |
| State Management | Zustand (lightweight, performant) |
| HTTP Client | Axios |
| Video Player | react-native-video (ExoPlayer backend on Android) |
| Storage | react-native-mmkv (fast key-value) + SQLite for addon/watchlist data |
| UI Components | Custom components with react-native-reanimated for animations |
| Icons | react-native-vector-icons (MaterialCommunityIcons) |
| Image Loading | react-native-fast-image |
| Torrent Support | WebTorrent integration via a background Node service or native module |
| Build | Gradle / Android SDK 34 |

### Required Dependencies

```bash
npx react-native init StreamVault --template react-native-template-typescript
cd StreamVault

# Core
npm install @react-navigation/native @react-navigation/stack @react-navigation/bottom-tabs
npm install react-native-screens react-native-safe-area-context react-native-gesture-handler
npm install zustand axios react-native-mmkv
npm install react-native-sqlite-storage

# Media
npm install react-native-video
npm install react-native-fast-image

# UI
npm install react-native-reanimated react-native-vector-icons
npm install react-native-linear-gradient
npm install react-native-modal

# Utilities
npm install lodash debounce-promise
npm install @react-native-community/netinfo
```

---

## Architecture

```
src/
├── api/
│   ├── addonClient.ts          # Stremio addon protocol client
│   ├── addonManager.ts         # Install/remove/list addons
│   ├── addonTypes.ts           # TypeScript types for addon protocol
│   └── cinemeta.ts             # Default Cinemeta addon integration
├── components/
│   ├── common/
│   │   ├── Card.tsx            # Movie/show poster card
│   │   ├── HeroCarousel.tsx    # Featured content carousel
│   │   ├── Row.tsx             # Horizontal scrollable row
│   │   ├── SearchBar.tsx       # Search input
│   │   ├── LoadingSpinner.tsx
│   │   ├── Badge.tsx           # Rating/quality badges
│   │   └── Toast.tsx           # Notification toasts
│   ├── catalog/
│   │   ├── CatalogGrid.tsx     # Grid view of catalog items
│   │   ├── CatalogRow.tsx      # Single row from a catalog
│   │   └── CatalogFilter.tsx   # Genre/type filters
│   ├── detail/
│   │   ├── DetailHero.tsx      # Background image + title overlay
│   │   ├── EpisodeList.tsx     # Season/episode picker for series
│   │   ├── StreamList.tsx      # Available streams from all addons
│   │   ├── StreamItem.tsx      # Single stream option
│   │   └── CastRow.tsx         # Cast/crew horizontal list
│   ├── player/
│   │   ├── VideoPlayer.tsx     # Full-screen video player
│   │   ├── PlayerControls.tsx  # Play/pause/seek/volume/subtitles
│   │   └── SubtitleOverlay.tsx # Subtitle rendering
│   └── addon/
│       ├── AddonCard.tsx       # Addon display card
│       ├── AddonInstaller.tsx  # URL input + install flow
│       └── AddonCatalog.tsx    # Browse available addons
├── screens/
│   ├── HomeScreen.tsx          # Main screen with catalog rows
│   ├── DiscoverScreen.tsx      # Browse/filter all content
│   ├── SearchScreen.tsx        # Global search across all addons
│   ├── DetailScreen.tsx        # Movie/series detail page
│   ├── PlayerScreen.tsx        # Video playback
│   ├── LibraryScreen.tsx       # Watchlist / continue watching / favorites
│   ├── AddonsScreen.tsx        # Manage installed addons
│   ├── AddonBrowseScreen.tsx   # Browse community addons
│   ├── SettingsScreen.tsx      # App settings
│   └── CalendarScreen.tsx      # Upcoming episodes calendar
├── store/
│   ├── addonStore.ts           # Installed addons state
│   ├── libraryStore.ts         # Watchlist/favorites/history
│   ├── playerStore.ts          # Playback state
│   └── settingsStore.ts        # App preferences
├── utils/
│   ├── colors.ts               # Theme colors
│   ├── dimensions.ts           # Responsive sizing
│   ├── formatters.ts           # Runtime, date, size formatters
│   └── debridService.ts        # Real-Debrid / AllDebrid integration
├── hooks/
│   ├── useAddon.ts             # Addon data fetching hooks
│   ├── useCatalog.ts           # Catalog pagination
│   ├── useStreams.ts           # Stream resolution
│   └── usePlayer.ts           # Player state management
└── navigation/
    ├── AppNavigator.tsx        # Root navigator
    ├── TabNavigator.tsx        # Bottom tab navigation
    └── types.ts                # Navigation type definitions
```

---

## Stremio Addon Protocol Implementation

This is the most critical part of the app. The addon protocol MUST be implemented exactly as specified to ensure compatibility with all existing Stremio addons.

### Addon Protocol Overview

Stremio addons are remote HTTP servers. The app communicates with them via simple GET requests. No code from addons runs on the device.

**Base pattern:** `GET {addonBaseUrl}/{resource}/{type}/{id}.json`

### TypeScript Types (addonTypes.ts)

```typescript
// ===== MANIFEST =====
interface AddonManifest {
  id: string;                    // e.g. "org.example.myaddon"
  version: string;               // semver
  name: string;
  description?: string;
  logo?: string;                 // URL to addon logo
  background?: string;           // URL to background image
  contactEmail?: string;
  types: ContentType[];          // ["movie", "series", "channel", "tv"]
  resources: (string | ResourceDescriptor)[];  // ["catalog", "meta", "stream", "subtitles"]
  catalogs: CatalogDescriptor[];
  idPrefixes?: string[];         // e.g. ["tt"] for IMDB IDs
  behaviorHints?: {
    adult?: boolean;
    p2p?: boolean;
    configurable?: boolean;
    configurationRequired?: boolean;
  };
  config?: ConfigOption[];
}

type ContentType = "movie" | "series" | "channel" | "tv" | "anime" | "other";

interface ResourceDescriptor {
  name: string;                  // "catalog" | "meta" | "stream" | "subtitles"
  types?: ContentType[];
  idPrefixes?: string[];
}

interface CatalogDescriptor {
  type: ContentType;
  id: string;                    // unique per addon
  name: string;
  extra?: ExtraDescriptor[];
}

interface ExtraDescriptor {
  name: string;                  // "search" | "genre" | "skip" | "top"
  isRequired?: boolean;
  options?: string[];            // e.g. genre options
  optionsLimit?: number;
}

interface ConfigOption {
  key: string;
  type: "text" | "number" | "password" | "checkbox" | "select";
  title?: string;
  required?: boolean;
  options?: string[];
  default?: string;
}

// ===== CATALOG RESPONSE =====
interface CatalogResponse {
  metas: MetaPreview[];
  hasMore?: boolean;             // pagination hint
}

interface MetaPreview {
  id: string;                    // IMDB ID (tt1234567) or addon-specific
  type: ContentType;
  name: string;
  poster?: string;               // URL to poster image
  posterShape?: "square" | "regular" | "landscape";  // default: "regular" (2:3)
  background?: string;
  logo?: string;
  description?: string;
  releaseInfo?: string;          // year or year range "2019-2023"
  imdbRating?: string;
  genres?: string[];
  links?: Link[];
}

// ===== META RESPONSE =====
interface MetaResponse {
  meta: MetaDetail;
}

interface MetaDetail extends MetaPreview {
  cast?: string[];
  director?: string[];
  writer?: string[];
  awards?: string;
  website?: string;
  runtime?: string;              // e.g. "2h 3min"
  language?: string;
  country?: string;
  trailers?: Trailer[];
  videos?: Video[];              // episodes for series
  behaviorHints?: {
    defaultVideoId?: string;
    hasScheduledVideos?: boolean;
  };
}

interface Video {
  id: string;                    // for series: "tt1234567:1:1" (imdbId:season:episode)
  title: string;
  season?: number;
  episode?: number;
  released?: string;             // ISO date
  overview?: string;
  thumbnail?: string;
  streams?: Stream[];            // some addons embed streams in meta
}

interface Trailer {
  source: string;                // YouTube ID
  type: "Trailer" | "Clip";
}

interface Link {
  name: string;
  category: string;
  url: string;
}

// ===== STREAM RESPONSE =====
interface StreamResponse {
  streams: Stream[];
}

interface Stream {
  // One of these is required:
  url?: string;                  // direct HTTP/HTTPS/RTMP stream URL
  ytId?: string;                 // YouTube video ID
  infoHash?: string;             // torrent info hash
  fileIdx?: number;              // file index within torrent
  externalUrl?: string;          // URL to open in browser

  name?: string;                 // stream name/source (shown to user)
  title?: string;                // additional info (quality, size, etc.)
  description?: string;

  subtitles?: SubtitleTrack[];

  behaviorHints?: {
    notWebReady?: boolean;
    bingeGroup?: string;         // for auto-selecting next episode stream
    countryWhitelist?: string[];
    countryBlacklist?: string[];
    proxyHeaders?: {
      request?: Record<string, string>;
      response?: Record<string, string>;
    };
    videoHash?: string;          // OpenSubtitles hash
    videoSize?: number;          // bytes
    filename?: string;
  };
}

// ===== SUBTITLE RESPONSE =====
interface SubtitleResponse {
  subtitles: SubtitleTrack[];
}

interface SubtitleTrack {
  id: string;
  url: string;                   // URL to .srt or .vtt file
  lang: string;                  // ISO 639-2 language code
  label?: string;                // display name
}
```

### Addon Client Implementation (addonClient.ts)

```typescript
// Core addon client - fetches data from addon servers
class AddonClient {
  private manifest: AddonManifest;
  private baseUrl: string;

  constructor(transportUrl: string, manifest: AddonManifest) {
    // transportUrl is the manifest URL minus /manifest.json
    this.baseUrl = transportUrl.replace(/\/manifest\.json$/, '');
    this.manifest = manifest;
  }

  // Install addon by fetching its manifest
  static async fromUrl(manifestUrl: string): Promise<AddonClient> {
    const response = await axios.get(manifestUrl);
    const manifest = response.data as AddonManifest;
    return new AddonClient(manifestUrl, manifest);
  }

  // Check if addon supports a given resource + type + id
  supportsResource(resource: string, type: ContentType, id?: string): boolean {
    const res = this.manifest.resources.find(r =>
      typeof r === 'string' ? r === resource : r.name === resource
    );
    if (!res) return false;

    if (typeof res === 'object') {
      if (res.types && !res.types.includes(type)) return false;
      if (id && res.idPrefixes && !res.idPrefixes.some(p => id.startsWith(p))) return false;
    }

    return true;
  }

  // GET /catalog/{type}/{id}.json
  // GET /catalog/{type}/{id}/{extra}.json (with search, genre, skip)
  async getCatalog(type: ContentType, catalogId: string, extra?: Record<string, string>): Promise<CatalogResponse> {
    let path = `/catalog/${type}/${catalogId}`;
    if (extra) {
      const extraStr = Object.entries(extra)
        .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
        .join('&');
      path += `/${extraStr}`;
    }
    const response = await axios.get(`${this.baseUrl}${path}.json`);
    return response.data;
  }

  // GET /meta/{type}/{id}.json
  async getMeta(type: ContentType, id: string): Promise<MetaResponse> {
    const response = await axios.get(`${this.baseUrl}/meta/${type}/${id}.json`);
    return response.data;
  }

  // GET /stream/{type}/{id}.json
  async getStreams(type: ContentType, id: string): Promise<StreamResponse> {
    const response = await axios.get(`${this.baseUrl}/stream/${type}/${id}.json`);
    return response.data;
  }

  // GET /subtitles/{type}/{id}.json
  // Extra can include videoHash, videoSize for OpenSubtitles matching
  async getSubtitles(type: ContentType, id: string, extra?: Record<string, string>): Promise<SubtitleResponse> {
    let path = `/subtitles/${type}/${id}`;
    if (extra) {
      const extraStr = Object.entries(extra)
        .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
        .join('&');
      path += `/${extraStr}`;
    }
    const response = await axios.get(`${this.baseUrl}${path}.json`);
    return response.data;
  }
}
```

### Addon Manager (addonManager.ts)

```typescript
// Manages installed addons, persists to storage
class AddonManager {
  private addons: Map<string, { client: AddonClient; manifest: AddonManifest; transportUrl: string }>;

  // Install addon from manifest URL
  async installAddon(manifestUrl: string): Promise<AddonManifest>;

  // Remove addon by ID
  removeAddon(addonId: string): void;

  // Get all installed addons
  getInstalledAddons(): AddonManifest[];

  // Get all catalogs from all installed addons (aggregated)
  getAllCatalogs(): { addon: AddonManifest; catalog: CatalogDescriptor }[];

  // Query all relevant addons for streams (parallel)
  async getStreamsFromAll(type: ContentType, id: string): Promise<{ addon: AddonManifest; streams: Stream[] }[]>;

  // Query all relevant addons for subtitles (parallel)
  async getSubtitlesFromAll(type: ContentType, id: string, extra?: Record<string, string>): Promise<SubtitleTrack[]>;

  // Search across all addons that support search
  async searchAll(query: string, type?: ContentType): Promise<MetaPreview[]>;

  // Persist installed addons to storage
  async save(): Promise<void>;

  // Load installed addons from storage
  async load(): Promise<void>;
}
```

### Default Addons

These should be pre-installed on first launch:

1. **Cinemeta** — `https://v3-cinemeta.strem.io/manifest.json`
   - Provides movie and series metadata and catalogs
   - This is the primary metadata source (handles all IMDB IDs)

2. **OpenSubtitles** — `https://opensubtitles-v3.strem.io/manifest.json`
   - Provides subtitles for movies and series

The user can then install any additional Stremio addon via URL.

### Addon URL Format Support

The app must support installing addons via:
- Direct manifest URL: `https://example.com/manifest.json`
- Stremio protocol link: `stremio://example.com/manifest.json`
- Deep link: `streamvault://addon/https://example.com/manifest.json`

Register intent filters for `stremio://` protocol so users can click "Install" on addon websites and it opens in StreamVault.

---

## Screens Specification

### 1. Home Screen

The main landing screen after opening the app.

**Layout:**
- Top: App logo + search icon + settings gear
- Hero carousel: 3-5 featured items (from catalog) with background image, title, description, and play button
- Below: Horizontal scrollable rows from installed addon catalogs
  - Each row has: title (e.g. "Popular Movies"), "See All" link, horizontal scroll of poster cards
  - Load first 20 items per catalog, paginate on scroll
- Bottom: Tab bar navigation

**Catalog Row Aggregation Logic:**
1. Collect all catalogs from all installed addons
2. Group by type (movies, series)
3. Display each catalog as a separate row
4. Order: Featured/trending first, then by addon install order

### 2. Discover Screen

Browse and filter content from all installed addon catalogs.

**Layout:**
- Top: Type selector (Movies / Series / All)
- Filter chips: Genre filters (aggregated from all addon catalogs that support genre extra)
- Content: Grid view (3 columns) of poster cards
- Infinite scroll with pagination (use "skip" extra)
- Pull to refresh

### 3. Search Screen

Global search across all installed addons.

**Layout:**
- Top: Large search input (auto-focus on enter)
- Results appear as you type (debounced 300ms)
- Results grouped by type (Movies section, Series section)
- Each result is a poster card with title and year
- "No results" state with suggestion to install more addons

**Search Implementation:**
- Query all installed addons that have catalogs with `extra: [{ name: "search" }]`
- Run searches in parallel across all addons
- Deduplicate results by IMDB ID
- Sort by relevance (exact title match first)

### 4. Detail Screen

Full detail page for a movie or series.

**Layout:**
- Background: Blurred backdrop image
- Hero area: Poster, title, year, runtime, rating (IMDb), genres
- Action buttons: Play (movies), Add to Library, Share
- Tabs:
  - **Overview**: Description, cast, director, trailer button
  - **Streams** (movies): List of available streams from all addons
  - **Episodes** (series): Season selector dropdown → episode list
  - **Similar**: Related content (if addon provides links)

**Stream Resolution:**
- When detail page opens for a movie, immediately query all relevant addons for streams in parallel
- Display streams sorted by: quality indicator, source name
- Each stream item shows: addon name, stream title (quality/size info), play button
- For series: resolve streams when user selects an episode

**Stream Item Display:**
```
[Addon Logo] Addon Name
Stream Title (e.g. "1080p BluRay - 2.1GB")
[Play Button]
```

### 5. Player Screen

Full-screen video player.

**Features:**
- ExoPlayer backend (via react-native-video)
- Controls: play/pause, seek bar with preview, rewind 10s, forward 10s
- Volume and brightness gestures (swipe left = brightness, swipe right = volume)
- Subtitle selection (from addon subtitles + embedded)
- Quality selection (if multiple stream URLs available)
- Picture-in-picture support
- Resume playback (save position to library)
- Lock screen controls / notification player
- Double tap sides to seek ±10s
- Long press for 2x speed

**Supported Stream Types:**
- `url`: Direct HTTP/HTTPS playback via ExoPlayer
- `ytId`: Open in YouTube app or use youtube-dl to extract stream URL
- `infoHash`: Torrent streaming (see Torrent Support section)
- `externalUrl`: Open in external browser

### 6. Library Screen

User's personal collection.

**Sections:**
- **Continue Watching**: Items with saved playback position
- **Watchlist**: User-added items (bookmarked)
- **Favorites**: Marked as favorite
- **History**: Recently watched

**Data Storage:**
- All library data stored locally in SQLite
- Each entry stores: meta ID, type, name, poster, addon source, playback position, timestamp

### 7. Addons Screen

Manage installed addons.

**Layout:**
- "Install Addon" button at top (opens URL input modal)
- List of installed addons:
  - Addon logo, name, version, description
  - Types it provides (movie/series badges)
  - Resources it provides (catalog/stream/subtitles badges)
  - Toggle enabled/disabled
  - Remove button (with confirmation)
- "Browse Community Addons" button → opens AddonBrowseScreen

**Install Flow:**
1. User enters manifest URL or pastes stremio:// link
2. App fetches manifest.json
3. Shows addon preview: name, description, what it provides
4. If addon has `config`, show configuration form
5. User confirms → addon saved to storage
6. Catalogs refresh with new addon content

### 8. Addon Browse Screen

Browse community addons (from Stremio's community addon catalog).

**Implementation:**
- Fetch the community addon catalog from: `https://stremio-addons.netlify.app/catalog.json`
  (or use any available addon catalog endpoint)
- Display addons as cards with: logo, name, description, install button
- Filter by type: All / Movies / Series / Subtitles / Channels
- Search addons by name

### 9. Settings Screen

App configuration.

**Options:**
- **Playback**
  - Default quality preference (Auto / 1080p / 720p / 480p)
  - Default subtitle language
  - Auto-play next episode
  - Hardware acceleration toggle
- **Debrid Service** (see Debrid Integration section)
  - Real-Debrid API key
  - AllDebrid API key
  - Premiumize API key
- **Appearance**
  - Theme (Dark / AMOLED Black / Light)
  - Poster size (Small / Medium / Large)
  - Language
- **Data**
  - Clear search history
  - Clear watch history
  - Export/Import library
  - Cache size / Clear cache
- **About**
  - Version
  - Licenses
  - GitHub / Website link

---

## UI/UX Design Specification

### Theme

Dark theme by default (media apps should always default to dark).

```typescript
const colors = {
  // Backgrounds
  background: '#0A0E17',        // Deep dark blue-black
  surface: '#141925',           // Card/surface background
  surfaceLight: '#1C2333',      // Elevated surface
  surfaceHighlight: '#252D3F',  // Hover/active state

  // Primary accent
  primary: '#7B5CFF',           // Purple accent (distinctive, not Stremio green)
  primaryDark: '#5A3FCC',
  primaryLight: '#9B82FF',

  // Text
  textPrimary: '#FFFFFF',
  textSecondary: '#8B95A8',
  textMuted: '#4A5568',

  // Semantic
  success: '#34D399',
  warning: '#FBBF24',
  error: '#F87171',
  info: '#60A5FA',

  // Rating
  imdbYellow: '#F5C518',

  // Gradients
  heroGradient: ['transparent', 'rgba(10,14,23,0.8)', '#0A0E17'],
};
```

### Typography

```typescript
const typography = {
  hero: { fontSize: 28, fontWeight: '700', letterSpacing: 0.5 },
  title: { fontSize: 20, fontWeight: '600' },
  subtitle: { fontSize: 16, fontWeight: '500' },
  body: { fontSize: 14, fontWeight: '400' },
  caption: { fontSize: 12, fontWeight: '400' },
  badge: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase' },
};
```

### Poster Cards

- Default aspect ratio: 2:3 (regular), 1:1 (square), 16:9 (landscape)
- Rounded corners: 8dp
- Shadow elevation on Android
- On press: scale down 0.96 with spring animation
- Show: poster image, title (2 lines max), year, rating badge

### Animations

- Screen transitions: shared element transitions for poster → detail
- Row scrolling: smooth horizontal with momentum
- Skeleton loading: shimmer effect on placeholders
- Stream loading: pulsing dots animation
- Pull to refresh: custom animation

### Navigation

Bottom tab bar with 4 tabs:
1. **Home** (house icon) — HomeScreen
2. **Discover** (compass icon) — DiscoverScreen
3. **Library** (bookmark icon) — LibraryScreen
4. **Addons** (puzzle icon) — AddonsScreen

Search is accessible via icon in the header of Home and Discover.
Settings via gear icon in header.

---

## Debrid Service Integration

Many Stremio users use debrid services (Real-Debrid, AllDebrid, Premiumize) for faster, cached torrent streaming. This is a key feature for power users.

### How Debrid Works

1. User has a debrid account with API key
2. When a stream has an `infoHash` (torrent), instead of downloading the torrent:
   - Send the magnet link to the debrid service API
   - The debrid service either has it cached or downloads it on their fast servers
   - It returns a direct HTTPS download link
   - The app plays this direct link (much faster, no P2P exposure)

### Real-Debrid Integration (debridService.ts)

```typescript
class RealDebridService {
  private apiKey: string;
  private baseUrl = 'https://api.real-debrid.com/rest/1.0';

  // Check if torrent is cached
  async checkCache(infoHash: string): Promise<boolean>;

  // Add magnet and get download link
  async resolveStream(infoHash: string, fileIdx?: number): Promise<string>;

  // Get user account info
  async getAccountInfo(): Promise<{ username: string; premium: boolean; expiration: string }>;
}
```

### Stream Resolution Priority

When displaying streams, order them:
1. Debrid-cached torrent streams (instant playback)
2. Direct HTTP streams
3. Non-cached torrent streams
4. External URLs

Show a ⚡ badge on debrid-cached streams.

---

## Torrent Streaming

For users without a debrid service who want to play torrent streams (`infoHash`).

### Options (pick one during development):

**Option A: WebTorrent (JavaScript-based)**
- Use a headless WebTorrent instance in a background service
- Stream directly to the video player
- Pros: Pure JS, easier to integrate with React Native
- Cons: WebRTC-only peers by default, slower

**Option B: LibTorrent Native Module**
- Create a native Android module wrapping libtorrent
- Better performance, connects to all BitTorrent peers
- Pros: Fast, full peer connectivity
- Cons: Requires native code, more complex

**Option C: Local Streaming Server**
- Run a lightweight HTTP server on the device
- Torrent client downloads and serves via localhost
- Player connects to `http://localhost:PORT/stream`
- This is how Stremio does it (via their stremio-server)

**Recommended: Option C** — it's the most reliable and is the same approach Stremio uses.

---

## Deep Linking & Intent Filters

Register the following in `AndroidManifest.xml`:

```xml
<!-- Handle stremio:// protocol links for addon installation -->
<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="stremio" />
</intent-filter>

<!-- Handle our own deep links -->
<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="streamvault" />
</intent-filter>

<!-- Handle magnet links (for torrent streams) -->
<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="magnet" />
</intent-filter>
```

---

## Data Flow Examples

### Example: User opens app and browses movies

```
1. App loads → AddonManager.load() → loads installed addons from storage
2. HomeScreen mounts → getAllCatalogs() → returns list of all catalogs
3. For each catalog row:
   a. addonClient.getCatalog("movie", "top") → returns { metas: [...] }
   b. Render horizontal row of poster cards
4. User scrolls to end of row → getCatalog("movie", "top", { skip: "20" }) → more items
```

### Example: User taps on a movie

```
1. Navigate to DetailScreen with { id: "tt1254207", type: "movie" }
2. Fetch meta from relevant addons:
   a. cinemetaClient.getMeta("movie", "tt1254207") → full metadata
3. Display detail page with poster, description, cast, etc.
4. Simultaneously fetch streams from all relevant addons:
   a. addonClient1.getStreams("movie", "tt1254207") → { streams: [...] }
   b. addonClient2.getStreams("movie", "tt1254207") → { streams: [...] }
   c. (parallel, Promise.allSettled)
5. If debrid configured, check cache for torrent streams:
   a. realDebrid.checkCache(stream.infoHash) → boolean
6. Display aggregated, sorted stream list
7. User taps stream → resolve URL → navigate to PlayerScreen
```

### Example: User searches for content

```
1. User types "Breaking Bad" in search
2. Debounce 300ms
3. For each addon with search-capable catalogs:
   a. addonClient.getCatalog("series", catalogId, { search: "Breaking Bad" })
4. Aggregate results, deduplicate by ID
5. Display in grid
6. User taps result → DetailScreen
```

### Example: User installs an addon

```
1. User enters: https://torrentio.strem.fun/manifest.json
2. App fetches manifest.json
3. Displays preview: "Torrentio - Provides torrent streams for movies and series"
4. User confirms install
5. AddonManager stores manifest + URL
6. Home screen refreshes with new addon's catalogs
```

---

## Android TV Support

The app should also work on Android TV (leanback). This can be a Phase 2 feature but keep it in mind during architecture:

- Use react-native-tvos or handle TV focus management
- D-pad navigation support
- Larger poster cards for 10-foot UI
- No touch-specific gestures on TV (no swipe)
- Voice search integration

---

## Performance Requirements

- App launch to content visible: < 2 seconds
- Catalog row load: < 500ms
- Search results: < 1 second
- Stream resolution: < 3 seconds
- Image caching: aggressive, using FastImage cache
- Offline support: Library/watchlist available offline, stream history cached

---

## Build & Distribution

### Generating Release APK

```bash
cd android
./gradlew assembleRelease
# Output: android/app/build/outputs/apk/release/app-release.apk
```

### Signing

Generate a keystore for release builds:
```bash
keytool -genkeypair -v -storetype PKCS12 -keystore streamvault.keystore \
  -alias streamvault -keyalg RSA -keysize 2048 -validity 10000
```

Configure in `android/app/build.gradle`:
```gradle
signingConfigs {
    release {
        storeFile file('streamvault.keystore')
        storePassword System.getenv('KEYSTORE_PASSWORD')
        keyAlias 'streamvault'
        keyPassword System.getenv('KEY_PASSWORD')
    }
}
```

### App Identity

- Package name: `com.streamvault.app` (change to your actual package)
- App name: StreamVault
- Min SDK: 24 (Android 7.0)
- Target SDK: 34 (Android 14)

---

## Phase 1 — MVP (Build This First)

Focus on getting a working app with core features:

1. ✅ Project setup (React Native + TypeScript)
2. ✅ Stremio addon protocol client (full implementation)
3. ✅ Addon manager (install/remove/list)
4. ✅ Pre-installed Cinemeta + OpenSubtitles addons
5. ✅ Home screen with catalog rows
6. ✅ Search screen
7. ✅ Detail screen (movie + series with episodes)
8. ✅ Stream list (aggregated from all addons)
9. ✅ Video player (direct HTTP streams only)
10. ✅ Library (watchlist + continue watching)
11. ✅ Addon management screen
12. ✅ Settings (basic)
13. ✅ Dark theme UI

## Phase 2 — Enhanced Features

14. Torrent streaming support (local server approach)
15. Real-Debrid integration
16. Subtitle selection + rendering
17. Android TV support
18. Community addon browser
19. Calendar for upcoming episodes
20. Export/import library
21. Push notifications for new episodes

## Phase 3 — Premium & Polish

22. Built-in proxy/geo-unblock (Exalive integration)
23. Stream caching/pre-loading
24. User accounts + cloud sync
25. Multiple profiles
26. Chromecast support
27. Picture-in-picture
28. Widget for home screen

---

## Important Notes for Claude Code

1. **Start with the addon protocol client** — this is the foundation. Test it against Cinemeta (`https://v3-cinemeta.strem.io/manifest.json`) before building UI.

2. **Use TypeScript strictly** — no `any` types, proper interfaces for all addon responses.

3. **Handle errors gracefully** — addons can be slow, unavailable, or return malformed data. Every addon request should have timeouts (5s) and graceful fallbacks.

4. **Test with real addons** — install Cinemeta and verify catalog browsing works. Then test with a stream addon like Torrentio to verify stream resolution.

5. **The app must look professional** — this is going to the Play Store. No placeholder UI, no "TODO" screens. Every screen should be polished.

6. **Performance matters** — use FlatList with proper key extraction, memoize components, cache images aggressively, lazy load off-screen content.

7. **Don't forget the video player** — this is a media app. The player experience (controls, gestures, subtitles) is just as important as browsing.
