Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

reproxy

A local HTTP proxy for Dart/Flutter apps. Point it at any URL or file path, attach custom headers, and get back a local URL you can hand to a video player or a cast device (Chromecast, DLNA, AirPlay, etc.).

  • Remote HLS manifests (.m3u8) are rewritten so their child playlists, segments and keys are fetched through the proxy too, carrying the same headers — useful when the player/cast device can't set headers itself.
  • Everything else (mp4, images, any file) is streamed through with full range/seek support.
  • Per-source headers travel inside an opaque token, so many streams can be proxied at once without clobbering each other.

Why

Cast devices and many native players can't attach Referer, User-Agent or cookies to their requests, and CDNs often require them. reproxy sits on the device, fetches the real resource with the right headers, and exposes a plain local URL that any player can consume.

player / cast device ──▶ http://192.168.1.5:52345/proxy?token=…
                                      │  (adds your headers)
                                      ▼
                              real CDN / local file

Install

dependencies:
  reproxy:
    path: ../reproxy   # or a git/pub reference
import 'package:reproxy/reproxy.dart';

Usage

final proxy = ReproxyServer();

// Start listening. Both arguments are optional:
//   port    -> defaults to 52345 (use 0 for an OS-assigned port)
//   address -> defaults to the device LAN IP (deviceIp())
await proxy.start();
print(proxy.baseUrl); // http://192.168.1.5:52345

// Remote stream that needs headers:
final hls = proxy.proxyUrl(
  source: 'https://host/master.m3u8',
  headers: {
    'Referer': 'https://host',
    'User-Agent': 'Mozilla/5.0',
  },
);

// Local file (served with range support, no headers needed):
final file = proxy.proxyUrl(source: '/storage/emulated/0/video.mp4');

// Hand `hls` / `file` to your player or cast device.
// player.setUrl(hls);

// When you're done:
await proxy.stop();

proxyUrl works the same whether source is a http(s):// URL or an absolute file path — reproxy detects which it is.

Custom port / address

await proxy.start(port: 8080);                       // fixed port
await proxy.start(port: 0);                          // any free port
await proxy.start(address: '0.0.0.0');               // all interfaces
await proxy.start(address: '192.168.1.5', port: 52345);

Need the device IP yourself? deviceIp() is exported.

API

Member Description
ReproxyServer() Create an instance (start as many as you like).
start({int port = 52345, String? address}) Bind and listen. port: 0 = OS-assigned; address defaults to deviceIp().
proxyUrl({required String source, Map<String,String> headers = const {}}) Local URL for a remote URL or file path, embedding headers.
baseUrl http://<address>:<port> (throws if not started).
isRunning Whether the server is listening.
stop() Stop listening and release resources.
deviceIp() The device's primary LAN IPv4 (top-level function).

Trying a URL from the terminal

The repo ships a quick manual checker, example/try_url.dart:

# A URL
dart run example/try_url.dart 'https://host/master.m3u8?token=…'

# A URL with headers (Name:value pairs)
dart run example/try_url.dart 'https://host/master.m3u8' \
  'Referer:https://host' 'User-Agent:Mozilla/5.0'

# A local file
dart run example/try_url.dart '/path/to/video.mp4'

It starts the proxy on 127.0.0.1, prints the proxy URL and status, and for HLS shows the rewritten manifest and follows the first child to confirm the chain works end to end.

To check playback (not just the fetch), copy the printed proxy URL into a player:

ffplay "http://127.0.0.1:PORT/proxy?token=…"
# VLC: Open Network Stream → paste the URL

How it works

  • The proxy exposes a single route, GET|HEAD /proxy?token=….
  • The token is base64url(json({target, headers})) — no server-side state, so concurrent streams never share/overwrite headers.
  • Remote, HLS (content-type contains mpegurl or the path ends in .m3u8/.m3u): the manifest is fetched, and every child reference (EXT-X-MEDIA, EXT-X-KEY, EXT-X-MAP, variant playlists, segments, …) is resolved with Uri.resolve and rewritten to /proxy?token=… carrying the same headers. Handles relative, ../, root-relative and absolute references.
  • Remote, other: streamed straight through. Range, If-Range, If-Modified-Since and If-None-Match are forwarded so seeking and caching keep working; hop-by-hop and stale content-encoding/content-length headers are cleaned up.
  • Local files: served with range support (206 Partial Content), correct MIME type and HEAD handling.
  • Permissive CORS is added to every response (including the range headers players need).

Notes & limitations

  • Manifests are returned as UTF-8 bytes (the spec for .m3u8). If a tool shows mojibake, it's the tool decoding as latin1 — the bytes on the wire are fine.
  • Signed/expiring URLs work as long as the signature is valid for the proxy's outgoing request (some CDNs bind the signature to a client IP).
  • Local .m3u8 files are served as-is (no rewriting of on-disk manifests).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages