mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-22 14:38:06 +02:00
feat: Implement new video player screen with controls for live, VOD, and series streams, integrating with an external player via iframe messaging.
This commit is contained in:
1 parent
5069e92bb7
commit
62fc19598a
3 files changed
+50
-38
No files matched your search
@@ -353,47 +353,59 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
|||||||
} else {
|
} else {
|
||||||
// For VOD and Series
|
// For VOD and Series
|
||||||
|
|
||||||
// FORCE API STREAMING (FFMPEG)
|
// For VOD and Series
|
||||||
// We always use the backend /api/stream endpoint because it handles audio transcoding (to AAC)
|
|
||||||
// which is required for browsers to play content with AC3/DTS audio.
|
|
||||||
// For 'High' quality, the backend uses '-c:v copy', so video quality is preserved (Direct Stream).
|
|
||||||
setState(() {
|
|
||||||
_statusMessage = 'Preparing stream...';
|
|
||||||
});
|
|
||||||
|
|
||||||
final baseUrl = html.window.location.origin;
|
// Determine play mode: Direct (Proxy) vs Transcode (FFmpeg)
|
||||||
final vodStreamUrl = widget.streamType == StreamType.vod
|
// Default to Direct/Proxy because it preserves duration metadata and seeking capability (via Range headers)
|
||||||
? xtreamService.getVodStreamUrl(currentStreamId, widget.containerExtension)
|
// Only use Transcode if explicitly FORCED (e.g. for audio compatibility issues like AC3/DTS on some browsers)
|
||||||
: xtreamService.getSeriesStreamUrl(currentStreamId, widget.containerExtension);
|
|
||||||
|
|
||||||
final encodedUrl = Uri.encodeComponent(vodStreamUrl);
|
|
||||||
|
|
||||||
// Read settings for VOD quality
|
|
||||||
final settings = ref.read(iptvSettingsProvider);
|
final settings = ref.read(iptvSettingsProvider);
|
||||||
|
final baseUrl = html.window.location.origin;
|
||||||
// Map quality enum to string (using if-else to avoid switch exhaustivity issues)
|
bool useTranscode = settings.transcodingMode == TranscodingMode.forced;
|
||||||
String qualityParam = 'medium';
|
|
||||||
if (settings.streamQuality == StreamQuality.low) {
|
setState(() {
|
||||||
qualityParam = 'low';
|
_statusMessage = useTranscode ? 'Preparing stream...' : 'Loading video...';
|
||||||
} else if (settings.streamQuality == StreamQuality.high) {
|
});
|
||||||
qualityParam = 'high';
|
|
||||||
|
if (useTranscode) {
|
||||||
|
// Transcoding Mode (FFmpeg pipe)
|
||||||
|
final encodedUrl = Uri.encodeComponent(
|
||||||
|
widget.streamType == StreamType.vod
|
||||||
|
? xtreamService.getVodStreamUrl(currentStreamId, widget.containerExtension)
|
||||||
|
: xtreamService.getSeriesStreamUrl(currentStreamId, widget.containerExtension)
|
||||||
|
);
|
||||||
|
|
||||||
|
String qualityParam = 'medium';
|
||||||
|
if (settings.streamQuality == StreamQuality.low) qualityParam = 'low';
|
||||||
|
else if (settings.streamQuality == StreamQuality.high) qualityParam = 'high';
|
||||||
|
|
||||||
|
// Calculate start time for seeking support
|
||||||
|
double startSeconds = startTimeOverride ?? 0;
|
||||||
|
if (startTimeOverride == null && _contentId.isNotEmpty) {
|
||||||
|
final positions = ref.read(playbackPositionsProvider);
|
||||||
|
final saved = positions.getPosition(_contentId);
|
||||||
|
if (saved > 0) startSeconds = saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We force extension to .ts for mpegts.js compatibility
|
||||||
|
hlsUrl = '$baseUrl/api/stream/$currentStreamId?url=$encodedUrl&quality=$qualityParam&start=${startSeconds.round()}&ext=.ts';
|
||||||
|
debugPrint('PlayerScreen: Streaming VOD (Transcoded): $hlsUrl');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Direct/Proxy Mode (Preserves Duration)
|
||||||
|
final rawUrl = widget.streamType == StreamType.vod
|
||||||
|
? '${widget.playlist.dns}/movie/${widget.playlist.username}/${widget.playlist.password}/$currentStreamId.${widget.containerExtension}'
|
||||||
|
: '${widget.playlist.dns}/series/${widget.playlist.username}/${widget.playlist.password}/$currentStreamId.${widget.containerExtension}';
|
||||||
|
|
||||||
|
// Force use of local proxy /api/xtream/ to handle CORS and Range headers correctly
|
||||||
|
final proxyPath = '/api/xtream/$rawUrl';
|
||||||
|
hlsUrl = '$baseUrl$proxyPath';
|
||||||
|
|
||||||
|
// Append start time for direct play?
|
||||||
|
// HTML5 video handles seeking naturally via headers, but if we want to resume:
|
||||||
|
// We have to seek AFTER metadata is loaded via JS (_seekTo called in onMessage logic).
|
||||||
|
|
||||||
|
debugPrint('PlayerScreen: Streaming VOD (Direct Proxy): $hlsUrl');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate start time for seeking support
|
|
||||||
// If override provided (seeking), use it. Else check provider resume.
|
|
||||||
double startSeconds = startTimeOverride ?? 0;
|
|
||||||
if (startTimeOverride == null && _contentId.isNotEmpty) {
|
|
||||||
final positions = ref.read(playbackPositionsProvider);
|
|
||||||
final saved = positions.getPosition(_contentId);
|
|
||||||
if (saved > 0) startSeconds = saved;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct URL with start param
|
|
||||||
// Note: We force extension to .ts for mpegts.js compatibility
|
|
||||||
final streamEndpoint = '$baseUrl/api/stream/$currentStreamId?url=$encodedUrl&quality=$qualityParam&start=${startSeconds.round()}&ext=.ts';
|
|
||||||
|
|
||||||
debugPrint('PlayerScreen: Streaming VOD (Audio Fix enabled): $streamEndpoint');
|
|
||||||
hlsUrl = streamEndpoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Reference in new issue
Block a user