# Go Video Source Resolution Engine

## Architecture

```
HTTP Server (Fiber) → Provider Registry → Site Providers → Embed Sources → Extractor Registry
                                                              ↓
                                                        Resolver → HLS Proxy
```

| Layer | Responsibility | Example |
|---|---|---|
| Server | Routes, CORS, rate limiting, health | `app.Get("/links/movie/:id")` |
| Provider Registry | Manage site scrapers, parallel dispatch | `providers.GetAllProviders()` |
| Site Providers | Scrape movie/TV sites for embed URLs | Sflix, CineCalidad |
| Embed Sources | TMDB ID → embed aggregator URL templates | `vidsrc.to/embed/movie/{id}` |
| Extractor Registry | Map hoster domains → resolution funcs | `Register(&VoeExtractor{})` |
| Extractors | Resolve embed URLs → m3u8 video | Voe, StreamTape, Rabbitstream |
| HLS Proxy | Proxy manifests + segments | `/proxy/hls/manifest?url=` |

## Provider Interface (Go)

```go
type SiteProvider interface {
    Name() string
    BaseURL() string
    Language() string
    GetHome() ([]models.Category, error)
    Search(query string, page int) ([]models.AppAdapterItem, error)
    GetMovie(id string) (*models.Movie, error)
    GetTvShow(id string) (*models.TvShow, error)
    GetServers(id string) ([]models.Server, error)
}
```

Auto-register: `providers.RegisterProvider(NewXxxProvider())` in `init()`.

## Extractor Interface (Go)

```go
type Extractor interface {
    Name() string
    MainURL() string
    Extract(link string) (*models.Video, error)
}
```

Auto-register: `extractors.Register(&XxxExtractor{})` in `init()`.

## Porting Kotlin Extractors to Go

### Simple (regex-based) — ~80% of hosters

```go
type XxxExtractor struct{}
func (e *XxxExtractor) Name() string    { return "Xxx" }
func (e *XxxExtractor) MainURL() string { return "xxx.com" }
func (e *XxxExtractor) Extract(link string) (*models.Video, error) {
    body, err := fetchString(link)
    if err != nil { return nil, err }
    if m := m3u8Regex.FindString(body); m != "" { return MakeVideo(m, nil), nil }
    // packed JS fallback
    result := UnpackJs(body)
    if result.Success {
        if m := m3u8Regex.FindString(result.Data); m != "" { return MakeVideo(m, nil), nil }
    }
    return nil, fmt.Errorf("no source")
}
func init() { Register(&XxxExtractor{}) }
```

### Complex (crypto-based)

| Technique | Used by | Go crypto |
|---|---|---|
| AES-CBC/PKCS5 + MD5 KDF | Rabbitstream, Megacloud, Chillx, Rpmvid | `DecryptAESCBC` + `MD5KDF` |
| RC4 KSA/PRGA (Vidsrc-style) | Vidsrc.to, Vidplay | `RC4Encode` + `DecryptRC4` |
| ROT13 → pattern replace → b64 → shift -3 → reverse → b64 | Voe.sx | `DecryptVoe` |
| 12 decrypt variants (hex, XOR, char shift, reverse) | Vidsrc.net | `DecryptVidsrcNet(methodID)` |
| P.A.C.K.E.R. deobfuscation | StreamWish, Supervideo, MixDrop | `UnpackJs` |
| ECDSA secp256r1 + AES-GCM | Filemoon | `crypto/ecdsa` + `crypto/aes` |

## HTML Parsing (Go vs Kotlin)

| Kotlin (Jsoup) | Go (regexp) |
|---|---|
| `doc.select("div.class > a")` | `<div class="[^"]*">.*?<a[^>]*>([^<]+)</a>` |
| `element.attr("href")` | `href="([^"]*)"` |
| `element.text()` | Text between `>` and `<` |
| `doc.selectFirst("script")` | `<script[^>]*>([\s\S]*?)</script>` |

For Cloudflare: use `refraction-networking/utls` with `HelloChrome_Auto`.

## Parallel Dispatch (Fiber)

```go
app.Get("/links/movie/:id", func(c *fiber.Ctx) error {
    var wg sync.WaitGroup; var mu sync.Mutex; var allSources []Source
    for _, p := range providers.GetAllProviders() {
        wg.Add(1); go func(prov SiteProvider) {
            defer wg.Done()
            ctx, cancel := context.WithTimeout(c.Context(), 10*time.Second)
            defer cancel()
            servers, _ := prov.GetServers(id)
            for _, s := range servers {
                mu.Lock(); allSources = append(allSources, Source{...}); mu.Unlock()
            }
        }(p)
    }
    wg.Wait(); return c.JSON(allSources)
})
```

## Pitfalls

- **Fiber `c.Params("*")` strips query strings.** Rebuild with `c.Request().URI().QueryString()` for proxy routes.
- **Duplicate init() registrations** cause silent overwrites. Names must be unique per domain.
- **Dead embed aggregators** are common. Use health monitoring + configurable source lists.
- **Cloudflare blocking** is normal for site scrapers. uTLS helps but some sites need full browser fingerprinting.
