# Applying Decompiled Learnings to Open-Source IPTV Bases

> Context: After extracting patterns from a closed-source IPTV app (TiviMate), you want to apply those learnings to an open-source fork rather than building from scratch.

## Evaluate Open-Source IPTV Bases

When selecting an Android TV IPTV player to fork, evaluate on:

| Criterion | StreamVault | OwnTV | M3UAndroid |
|---|---|---|---|
| Stars | 487 | 216 | 1.2k |
| Stack | Kotlin + Compose TV | Kotlin + Compose TV | Kotlin (Views) |
| License | **StreamVault OSL** (non-commercial, must credit) | **GPL-3.0** (must open forks) | Check repo |
| Providers | M3U, Xtream, Stalker, Jellyfin | M3U, Xtream | M3U |
| EPG | XMLTV + source priority + manual override | XMLTV | Basic |
| Player | Media3 ExoPlayer | Dual: libmpv + ExoPlayer | ExoPlayer |
| Activity | Jun 2026 | Hours ago (Jul 6) | May 2026 |

**License implications:**
- StreamVault OSL: Must credit original author (Davidona), keep ko-fi link visible, **cannot charge money**
- GPL-3.0: Can charge but **must open-source your fork**
- MIT: Can close-source and sell (if available)

## Apply Decompiled Values Per Layer

### Player / Buffer Config

TiviMate's approach: aggressive startup, generous buffer, moderate rebuffer.

| Parameter | Typical Default | TiviMate Value |
|---|---|---|
| Live minBuffer | 8,000ms | **50,000ms** |
| Live maxBuffer | 30,000ms | **100,000ms** |
| Playback startup | 1,500ms | **2,500ms** |
| Rebuffer threshold | 5,000ms | **5,000ms** |

Pattern: Add a new `TIVIMATE` preset to the `PlaybackBufferMode` enum and wire into the policy selector. Users can toggle without breaking existing behavior.

### M3U Parser

Add regex fast-path from TiviMate C4409.java:

```
TIVIMATE_EXTINF_DURATION = Pattern.compile("#EXTINF:\\s*([\\d\\.]+)\\b")
TIVIMATE_EXTINF_NAME = Pattern.compile("#EXTINF:[\\d\\.]+\\b,(.+)")
```

Create `parseExtinfFast()` that tries regex first, falls back to character-by-character on mismatch.

### EPG Timeline

TiviMate's deterministic pixel-per-minute formula:

```
programLeft = (startTime - windowStart) * pixelsPerMinute / 60000
programWidth = durationMs * pixelsPerMinute / 60000
```

Replace ratio-based positioning with this approach. Default 8dp/min.

### Xtream API Client

Non-obfuscated data models from `ar.tvplayer.core.data.network.xtreamcodes`:

```kotlin
class UserInfo(username, password, auth, message, auth_valid, is_trial, active_cons, max_connections, exp_date, tags)
class ServerInfo(url, port, https_port, server_protocol, rtmp_port, timezone, timestamp_now, timezone_name)
class UserAndServerInfo(user_info, server_info)
class CatchupData(day_offset, duration_minutes)
```

API endpoints:
- `player_api.php?username={u}&password={p}` → auth
- `player_api.php?action=live` → live channels
- `player_api.php?action=get_short_epg` → EPG
- `get.php?username={u}&password={p}&type=m3u_plus` → M3U

## Key Insight

The value of decompiling TiviMate isn't copying its UI (obfuscated garbage) — it's extracting **tuning constants, regex patterns, formula constants, and API field mappings** that represent years of iteration. These survive obfuscation because they're plain `const val` / `Pattern.compile()` / `import` statements ProGuard can't eliminate.
