diff --git a/src/screens/PlayerSettingsScreen.tsx b/src/screens/PlayerSettingsScreen.tsx index 9cb7ba5c..e808efe4 100644 --- a/src/screens/PlayerSettingsScreen.tsx +++ b/src/screens/PlayerSettingsScreen.tsx @@ -261,180 +261,7 @@ const PlayerSettingsScreen: React.FC = () => { }, ]} > - - - - - - - - {t('player.autoplay_title')} - - - {t('player.autoplay_desc')} - - - updateSetting('autoplayBestStream', value)} - trackColor={{ false: '#767577', true: currentTheme.colors.primary }} - thumbColor={settings.autoplayBestStream ? '#ffffff' : '#f4f3f4'} - ios_backgroundColor="#3e3e3e" - /> - - - - {/* Preferred Quality for Autoplay */} - - - - - - - - {t('player.preferred_quality_title') || 'Preferred Quality'} - - - {t('player.preferred_quality_desc') || 'Select preferred quality for autoplay'} - - - - - {([ - { id: '4K', label: '4K' }, - { id: '1080p', label: '1080p' }, - { id: '720p', label: '720p' }, - { id: '480p', label: '480p' }, - ] as const).map((option) => ( - updateSetting('autoplayPreferredQuality', option.id)} - style={[ - styles.optionButton, - settings.autoplayPreferredQuality === option.id && { backgroundColor: currentTheme.colors.primary }, - ]} - > - - {option.label} - - - ))} - - - - {/* Preferred Language for Autoplay */} - - - - - - - - {t('player.preferred_language_title') || 'Preferred Language'} - - - {t('player.preferred_language_desc') || 'Select preferred language for autoplay'} - - - - - {([ - { id: 'Any', label: t('common.any') || 'Any' }, - { id: 'English', label: t('settings.english') || 'English' }, - { id: 'Spanish', label: t('settings.spanish') || 'Spanish' }, - { id: 'French', label: t('settings.french') || 'French' }, - { id: 'German', label: t('settings.german') || 'German' }, - { id: 'Italian', label: t('settings.italian') || 'Italian' }, - { id: 'Portuguese', label: t('settings.portuguese') || 'Portuguese' }, - { id: 'Russian', label: t('settings.russian') || 'Russian' }, - { id: 'Hindi', label: t('settings.hindi') || 'Hindi' }, - { id: 'Chinese', label: t('settings.chinese') || 'Chinese' }, - { id: 'Japanese', label: t('settings.japanese') || 'Japanese' }, - { id: 'Korean', label: t('settings.korean') || 'Korean' }, - ] as const).map((option) => ( - updateSetting('autoplayPreferredLanguage', option.id)} - style={[ - styles.optionButton, - styles.optionButtonLanguage, - settings.autoplayPreferredLanguage === option.id && { backgroundColor: currentTheme.colors.primary }, - ]} - > - - {option.label} - - - ))} - - - - {/* Video Player Engine for Android */} + {/* Video Player Engine for Android */} {Platform.OS === 'android' && !settings.useExternalPlayer && ( <> diff --git a/src/screens/settings/PlaybackSettingsScreen.tsx b/src/screens/settings/PlaybackSettingsScreen.tsx index c3559e3c..8118cb8f 100644 --- a/src/screens/settings/PlaybackSettingsScreen.tsx +++ b/src/screens/settings/PlaybackSettingsScreen.tsx @@ -62,6 +62,19 @@ const SUBTITLE_SOURCE_OPTIONS = [ { value: 'any', label: 'Any Available', description: 'Use first available subtitle track' }, ]; +const AUTOPLAY_QUALITY_OPTIONS = [ + { id: '4320p', label: '8K' }, + { id: '4K', label: '4K' }, + { id: '3660p', label: '3660p' }, + { id: '1440p', label: '1440p' }, + { id: '1080p', label: '1080p' }, + { id: '720p', label: '720p' }, + { id: '480p', label: '480p' }, + { id: '360p', label: '360p' }, + { id: '240p', label: '240p' }, + { id: '140p', label: '140p' }, +]; + // Props for the reusable content component interface PlaybackSettingsContentProps { isTablet?: boolean; @@ -151,30 +164,55 @@ export const PlaybackSettingsContent: React.FC = ( const audioLanguageSheetRef = useRef(null); const subtitleLanguageSheetRef = useRef(null); const subtitleSourceSheetRef = useRef(null); + const autoplayQualitySheetRef = useRef(null); + const autoplayLanguageSheetRef = useRef(null); // Snap points const languageSnapPoints = useMemo(() => ['70%'], []); const sourceSnapPoints = useMemo(() => ['45%'], []); + const qualitySnapPoints = useMemo(() => ['45%'], []); // Handlers to present sheets - ensure only one is open at a time const openAudioLanguageSheet = useCallback(() => { subtitleLanguageSheetRef.current?.dismiss(); subtitleSourceSheetRef.current?.dismiss(); + autoplayQualitySheetRef.current?.dismiss(); + autoplayLanguageSheetRef.current?.dismiss(); setTimeout(() => audioLanguageSheetRef.current?.present(), 100); }, []); const openSubtitleLanguageSheet = useCallback(() => { audioLanguageSheetRef.current?.dismiss(); subtitleSourceSheetRef.current?.dismiss(); + autoplayQualitySheetRef.current?.dismiss(); + autoplayLanguageSheetRef.current?.dismiss(); setTimeout(() => subtitleLanguageSheetRef.current?.present(), 100); }, []); const openSubtitleSourceSheet = useCallback(() => { audioLanguageSheetRef.current?.dismiss(); subtitleLanguageSheetRef.current?.dismiss(); + autoplayQualitySheetRef.current?.dismiss(); + autoplayLanguageSheetRef.current?.dismiss(); setTimeout(() => subtitleSourceSheetRef.current?.present(), 100); }, []); + const openAutoplayQualitySheet = useCallback(() => { + audioLanguageSheetRef.current?.dismiss(); + subtitleLanguageSheetRef.current?.dismiss(); + subtitleSourceSheetRef.current?.dismiss(); + autoplayLanguageSheetRef.current?.dismiss(); + setTimeout(() => autoplayQualitySheetRef.current?.present(), 100); + }, []); + + const openAutoplayLanguageSheet = useCallback(() => { + audioLanguageSheetRef.current?.dismiss(); + subtitleLanguageSheetRef.current?.dismiss(); + subtitleSourceSheetRef.current?.dismiss(); + autoplayQualitySheetRef.current?.dismiss(); + setTimeout(() => autoplayLanguageSheetRef.current?.present(), 100); + }, []); + const isItemVisible = (itemId: string) => { if (!config?.items) return true; const item = config.items[itemId]; @@ -226,6 +264,16 @@ export const PlaybackSettingsContent: React.FC = ( subtitleSourceSheetRef.current?.dismiss(); }; + const handleSelectAutoplayQuality = (quality: string) => { + updateSetting('autoplayPreferredQuality', quality); + autoplayQualitySheetRef.current?.dismiss(); + }; + + const handleSelectAutoplayLanguage = (language: string) => { + updateSetting('autoplayPreferredLanguage', language); + autoplayLanguageSheetRef.current?.dismiss(); + }; + return ( <> {hasVisibleItems(['video_player']) && ( @@ -248,6 +296,38 @@ export const PlaybackSettingsContent: React.FC = ( )} + ( + updateSetting('autoplayBestStream', value)} + /> + )} + isTablet={isTablet} + /> + {settings?.autoplayBestStream && ( + <> + } + onPress={openAutoplayQualitySheet} + isTablet={isTablet} + /> + } + onPress={openAutoplayLanguageSheet} + isTablet={isTablet} + /> + + )} = ( })} + + {/* Autoplay Quality Bottom Sheet */} + + + {t('player.preferred_quality_title')} + + + {AUTOPLAY_QUALITY_OPTIONS.map((option) => { + const isSelected = option.id === (settings?.autoplayPreferredQuality || '1080p'); + return ( + handleSelectAutoplayQuality(option.id)} + > + + {option.label} + + {isSelected && ( + + )} + + ); + })} + + + + {/* Autoplay Language Bottom Sheet */} + + + {t('player.preferred_language_title')} + + + {[ + { id: 'Any', label: t('common.any') || 'Any' }, + { id: 'English', label: t('settings.english') || 'English' }, + { id: 'Spanish', label: t('settings.spanish') || 'Spanish' }, + { id: 'French', label: t('settings.french') || 'French' }, + { id: 'German', label: t('settings.german') || 'German' }, + { id: 'Italian', label: t('settings.italian') || 'Italian' }, + { id: 'Portuguese', label: t('settings.portuguese') || 'Portuguese' }, + { id: 'Russian', label: t('settings.russian') || 'Russian' }, + { id: 'Hindi', label: t('settings.hindi') || 'Hindi' }, + { id: 'Chinese', label: t('settings.chinese') || 'Chinese' }, + { id: 'Japanese', label: t('settings.japanese') || 'Japanese' }, + { id: 'Korean', label: t('settings.korean') || 'Korean' }, + ].map((option) => { + const isSelected = option.id === (settings?.autoplayPreferredLanguage || 'Any'); + return ( + handleSelectAutoplayLanguage(option.id)} + > + + {option.label} + + {isSelected && ( + + )} + + ); + })} + + ); }; diff --git a/src/screens/streams/useStreamsScreen.ts b/src/screens/streams/useStreamsScreen.ts index 396228fe..0e88faa0 100644 --- a/src/screens/streams/useStreamsScreen.ts +++ b/src/screens/streams/useStreamsScreen.ts @@ -22,6 +22,7 @@ import { TABLET_BREAKPOINT } from './constants'; import { filterStreamsByQuality, filterStreamsByLanguage, + getLanguageVariations, getQualityNumeric, inferVideoTypeFromUrl, sortStreamsByQuality, @@ -254,13 +255,20 @@ export const useStreamsScreen = () => { let languageMatchedStreams = allStreams; if (preferredLanguage && preferredLanguage !== 'Any') { languageMatchedStreams = allStreams.filter(item => { + const streamName = (item.stream.name || '').toLowerCase(); + const streamTitle = (item.stream.title || '').toLowerCase(); + const streamDesc = (item.stream.description || '').toLowerCase(); const streamLang = (item.stream.lang || '').toLowerCase(); - const prefLang = preferredLanguage.toLowerCase(); - // Match by name if lang is not set, or match by lang property - return streamLang === prefLang || - (item.stream.name || '').toLowerCase().includes(prefLang) || - (item.stream.title || '').toLowerCase().includes(prefLang) || - (item.stream.description || '').toLowerCase().includes(prefLang); + + const variations = getLanguageVariations(preferredLanguage); + + return variations.some(variant => { + const variantLower = variant.toLowerCase(); + return streamLang === variantLower || + streamName.includes(variantLower) || + streamTitle.includes(variantLower) || + streamDesc.includes(variantLower); + }); }); }