From 9b330b82265796b03ac2dcb709ebc8a6b0c58462 Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Thu, 19 Feb 2026 06:23:08 +0530 Subject: [PATCH] add forgot password link to AuthScreen and enhance URL normalization in SupabaseSyncService --- ...otlin-compiler-17947464936783636493.salive | 0 src/screens/AuthScreen.tsx | 21 +++++++++++++- src/services/supabaseSyncService.ts | 29 ++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) delete mode 100644 android/.kotlin/sessions/kotlin-compiler-17947464936783636493.salive diff --git a/android/.kotlin/sessions/kotlin-compiler-17947464936783636493.salive b/android/.kotlin/sessions/kotlin-compiler-17947464936783636493.salive deleted file mode 100644 index e69de29b..00000000 diff --git a/src/screens/AuthScreen.tsx b/src/screens/AuthScreen.tsx index 9bd9ef84..4033429f 100644 --- a/src/screens/AuthScreen.tsx +++ b/src/screens/AuthScreen.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { View, TextInput, Text, TouchableOpacity, StyleSheet, ActivityIndicator, SafeAreaView, KeyboardAvoidingView, Platform, Animated, Easing, Keyboard, StatusBar, useWindowDimensions } from 'react-native'; +import { View, TextInput, Text, TouchableOpacity, StyleSheet, ActivityIndicator, SafeAreaView, KeyboardAvoidingView, Platform, Animated, Easing, Keyboard, StatusBar, useWindowDimensions, Linking } from 'react-native'; import { mmkvStorage } from '../services/mmkvStorage'; import { LinearGradient } from 'expo-linear-gradient'; import { MaterialIcons } from '@expo/vector-icons'; @@ -425,6 +425,16 @@ const AuthScreen: React.FC = () => { + {mode === 'signin' && ( + Linking.openURL('https://nuvioapp.space/account/reset-password')} + activeOpacity={0.75} + style={styles.forgotPasswordButton} + > + Forgot password? + + )} + {/* Confirm Password (signup only) */} {mode === 'signup' && ( @@ -744,6 +754,15 @@ const styles = StyleSheet.create({ fontSize: 14, fontWeight: '500', }, + forgotPasswordButton: { + alignSelf: 'flex-end', + marginTop: -6, + marginBottom: 12, + }, + forgotPasswordText: { + fontSize: 13, + fontWeight: '600', + }, }); export default AuthScreen; diff --git a/src/services/supabaseSyncService.ts b/src/services/supabaseSyncService.ts index 2134edbc..6c4265bb 100644 --- a/src/services/supabaseSyncService.ts +++ b/src/services/supabaseSyncService.ts @@ -825,7 +825,11 @@ class SupabaseSyncService { } private normalizeUrl(url: string): string { - return url.trim().toLowerCase(); + let u = url.trim().toLowerCase(); + + u = u.replace(/\/manifest\.json\/?$/i, ''); + u = u.replace(/\/+$/, ''); + return u; } private toBigIntNumber(value: unknown): number { @@ -1063,14 +1067,37 @@ class SupabaseSyncService { .map((url) => this.normalizeUrl(url)) ); + // Build a set of currently-installed addon manifest IDs so we can also + // skip by ID (prevents duplicate installations of stream-providing addons + // that the URL check alone might miss due to URL format differences). + const installedAddonIds = new Set( + installed.map((addon) => addon.id).filter(Boolean) + ); + for (const row of rows || []) { if (!row.url) continue; const normalized = this.normalizeUrl(row.url); if (installedUrls.has(normalized)) continue; try { + // Pre-check: fetch manifest to see if this addon ID is already installed. + // This prevents creating duplicate installations for stream-providing + // addons whose URLs differ only by format (e.g. with/without manifest.json). + let manifest: Manifest | null = null; + try { + manifest = await stremioService.getManifest(row.url); + } catch { + // If manifest fetch fails, fall through to installAddon which will also fail and be caught below. + } + if (manifest?.id && installedAddonIds.has(manifest.id)) { + // Addon already installed under a different URL variant — skip. + logger.log(`[SupabaseSyncService] pullAddonsToLocal: skipping duplicate addon id=${manifest.id} url=${row.url}`); + installedUrls.add(normalized); + continue; + } await stremioService.installAddon(row.url); installedUrls.add(normalized); + if (manifest?.id) installedAddonIds.add(manifest.id); } catch (error) { logger.warn('[SupabaseSyncService] Failed to install synced addon:', row.url, error); }