feat: introduce core server with API, media streaming, Xtream proxy, and player UI

This commit is contained in:
Michael committed 2025-12-07 15:29:00 +01:00
1 parent 7372f51b19
commit b244f1f807
2 files changed
+15 -5

No files matched your search

+13 -3
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,
+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,