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 // Forward the Range header for seeking support
if (rangeHeader != null && rangeHeader.isNotEmpty) { 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'); print('Video streaming with Range: $rangeHeader');
} }
// Disable auto-decompression to strictly proxy the stream
client.autoUncompress = false;
final response = await req.close(); final response = await req.close();
// Get content type from response // 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) // 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) { 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 appropriate status code (200 for full, 206 for partial)
return Response( return Response(
response.statusCode, response.statusCode,
+2 -2
View File
@@ -735,11 +735,11 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
// EPG Overlay // EPG Overlay
if (widget.streamType == StreamType.live) if (widget.streamType == StreamType.live)
Positioned( Positioned(
bottom: 0, bottom: 100, // Move up above progress bar area/OS safe area
left: 0, left: 0,
right: 0, right: 0,
child: Container( child: Container(
padding: const EdgeInsets.only(bottom: 20), padding: const EdgeInsets.only(bottom: 8),
decoration: const BoxDecoration( decoration: const BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
begin: Alignment.bottomCenter, begin: Alignment.bottomCenter,