mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
Merge branch 'main' of https://github.com/tapframe/NuvioStreaming
This commit is contained in:
commit
1b9010435f
2 changed files with 73 additions and 6 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react';
|
||||
import { View, StyleSheet, ScrollView, StatusBar, Platform, Text, TouchableOpacity, Dimensions, TextInput } from 'react-native';
|
||||
import { View, StyleSheet, ScrollView, StatusBar, Platform, Text, TouchableOpacity, Dimensions, TextInput, ActivityIndicator } from 'react-native';
|
||||
import { useNavigation, useFocusEffect } from '@react-navigation/native';
|
||||
import { NavigationProp } from '@react-navigation/native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
|
@ -14,6 +14,7 @@ import { BottomSheetModal, BottomSheetScrollView, BottomSheetBackdrop } from '@g
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { SvgXml } from 'react-native-svg';
|
||||
import { toastService } from '../../services/toastService';
|
||||
import { introService } from '../../services/introService';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
|
||||
|
|
@ -79,14 +80,40 @@ export const PlaybackSettingsContent: React.FC<PlaybackSettingsContentProps> = (
|
|||
|
||||
const [introDbLogoXml, setIntroDbLogoXml] = useState<string | null>(null);
|
||||
const [apiKeyInput, setApiKeyInput] = useState(settings?.introDbApiKey || '');
|
||||
const [isVerifyingKey, setIsVerifyingKey] = useState(false);
|
||||
|
||||
const isMounted = useRef(true);
|
||||
|
||||
useEffect(() => {
|
||||
isMounted.current = true;
|
||||
return () => {
|
||||
isMounted.current = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setApiKeyInput(settings?.introDbApiKey || '');
|
||||
}, [settings?.introDbApiKey]);
|
||||
|
||||
const handleApiKeySubmit = () => {
|
||||
updateSetting('introDbApiKey', apiKeyInput);
|
||||
toastService.success(t('settings.items.api_key_saved', { defaultValue: 'API Key Saved' }));
|
||||
const handleApiKeySubmit = async () => {
|
||||
if (!apiKeyInput.trim()) {
|
||||
updateSetting('introDbApiKey', '');
|
||||
toastService.success(t('settings.items.api_key_cleared', { defaultValue: 'API Key Cleared' }));
|
||||
return;
|
||||
}
|
||||
|
||||
setIsVerifyingKey(true);
|
||||
const isValid = await introService.verifyApiKey(apiKeyInput);
|
||||
|
||||
if (!isMounted.current) return;
|
||||
setIsVerifyingKey(false);
|
||||
|
||||
if (isValid) {
|
||||
updateSetting('introDbApiKey', apiKeyInput);
|
||||
toastService.success(t('settings.items.api_key_saved', { defaultValue: 'API Key Saved' }));
|
||||
} else {
|
||||
toastService.error(t('settings.items.api_key_invalid', { defaultValue: 'Invalid API Key' }));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -271,8 +298,13 @@ export const PlaybackSettingsContent: React.FC<PlaybackSettingsContentProps> = (
|
|||
<TouchableOpacity
|
||||
style={styles.confirmButton}
|
||||
onPress={handleApiKeySubmit}
|
||||
disabled={isVerifyingKey}
|
||||
>
|
||||
<MaterialIcons name="check" size={24} color="black" />
|
||||
{isVerifyingKey ? (
|
||||
<ActivityIndicator size="small" color="black" />
|
||||
) : (
|
||||
<MaterialIcons name="check" size={24} color="black" />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -187,6 +187,40 @@ async function fetchFromIntroDb(imdbId: string, season: number, episode: number)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies an IntroDB API key
|
||||
*/
|
||||
export async function verifyApiKey(apiKey: string): Promise<boolean> {
|
||||
try {
|
||||
if (!apiKey) return false;
|
||||
|
||||
const response = await axios.post(`${INTRODB_API_URL}/submit`, {}, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
timeout: 5000,
|
||||
validateStatus: (status) => true // Handle status codes manually
|
||||
});
|
||||
|
||||
// 400 means Auth passed but payload was empty/invalid -> Key is Valid
|
||||
if (response.status === 400) return true;
|
||||
|
||||
// 200/201 would also mean valid (though unexpected with empty body)
|
||||
if (response.status === 200 || response.status === 201) return true;
|
||||
|
||||
// Explicitly handle auth failures
|
||||
if (response.status === 401 || response.status === 403) return false;
|
||||
|
||||
// Log warning for unexpected states (500, 429, etc.) but fail safe
|
||||
logger.warn(`[IntroService] Verification received unexpected status: ${response.status}`);
|
||||
return false;
|
||||
} catch (error: any) {
|
||||
logger.log('[IntroService] API Key verification failed:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits an intro timestamp to IntroDB
|
||||
*/
|
||||
|
|
@ -305,7 +339,8 @@ export async function getIntroTimestamps(
|
|||
export const introService = {
|
||||
getIntroTimestamps,
|
||||
getSkipTimes,
|
||||
submitIntro
|
||||
submitIntro,
|
||||
verifyApiKey
|
||||
};
|
||||
|
||||
export default introService;
|
||||
|
|
|
|||
Loading…
Reference in a new issue