Merge pull request #76 from R0m1k3/antigravity

Antigravity
This commit is contained in:
LogiFlow authored and GitHub committed 2025-12-07 15:29:18 +01:00
commit 87da1307bc
2 files changed
+50 -8

No files matched your search

+48 -6
View File
@@ -279,10 +279,17 @@ Future<Response> _streamVideoFile(Uri targetUrl, String? rangeHeader) async {
// Forward the Range header for seeking support
if (rangeHeader != null && rangeHeader.isNotEmpty) {
req.headers.set('Range', rangeHeader);
// Ensure we request bytes
if (!rangeHeader.startsWith('bytes=')) {
rangeHeader = 'bytes=$rangeHeader';
}
req.headers.set(HttpHeaders.rangeHeader, rangeHeader);
print('Video streaming with Range: $rangeHeader');
}
// Disable auto-decompression to strictly proxy the stream
client.autoUncompress = false;
final response = await req.close();
// Get content type from response
@@ -303,11 +310,14 @@ Future<Response> _streamVideoFile(Uri targetUrl, String? rangeHeader) async {
}
// Add Content-Range if this is a partial response (206)
final contentRange = response.headers.value('content-range');
final contentRange = response.headers.value(HttpHeaders.contentRangeHeader);
if (contentRange != null) {
responseHeaders['content-range'] = contentRange;
responseHeaders[HttpHeaders.contentRangeHeader] = contentRange;
}
// Propagate Accept-Ranges
responseHeaders[HttpHeaders.acceptRangesHeader] = 'bytes';
// Return appropriate status code (200 for full, 206 for partial)
return Response(
response.statusCode,
@@ -418,6 +428,8 @@ Handler _createStreamHandler() {
// Get parameters
final iptvUrl = request.url.queryParameters['url'];
final quality = request.url.queryParameters['quality'] ?? 'high';
if (iptvUrl == null || iptvUrl.isEmpty) {
return Response.badRequest(body: 'Missing url parameter');
}
@@ -452,9 +464,39 @@ Handler _createStreamHandler() {
// Output format: MPEG-TS for streaming (compatible with mpegts.js)
'-f', 'mpegts',
// Video: Copy is BEST for performance (0% CPU)
// Browsers support H.264 well.
'-c:v', 'copy',
// Video: Transcode based on quality
// High = Copy (efficient), Low/Medium = Transcode to H.264 (compatible)
if (quality == 'high') {
ffmpegArgs.addAll(['-c:v', 'copy']);
} else {
// Transcode to H.264 (Baseline profile for max mobile compatibility)
ffmpegArgs.addAll([
'-c:v', 'libx264',
'-preset', 'ultrafast', // Critical for live streaming
'-tune', 'zerolatency',
'-profile:v', 'baseline',
'-level', '3.0',
'-pix_fmt', 'yuv420p', // Ensure standard pixel format for web
'-g', '60', // Keyframe interval (2s at 30fps) for seeking
]);
if (quality == 'low') {
// Low: ~480p, 800k
ffmpegArgs.addAll([
'-vf', 'scale=-2:480',
'-b:v', '800k',
'-maxrate', '800k',
'-bufsize', '1600k'
]);
} else {
// Medium: Original res (or cap at 720p?), 2500k
ffmpegArgs.addAll([
'-b:v', '2500k',
'-maxrate', '2500k',
'-bufsize', '5000k'
]);
}
}
// Audio: Transcode to AAC is SAFEST for browsers
// (Many IPTV streams typically use MP2/AC3 which browsers hate)
+2 -2
View File
@@ -735,11 +735,11 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
// EPG Overlay
if (widget.streamType == StreamType.live)
Positioned(
bottom: 0,
bottom: 100, // Move up above progress bar area/OS safe area
left: 0,
right: 0,
child: Container(
padding: const EdgeInsets.only(bottom: 20),
padding: const EdgeInsets.only(bottom: 8),
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,