diff --git a/src-tauri/src/api_client.rs b/src-tauri/src/api_client.rs index 04acb38..dc82e59 100644 --- a/src-tauri/src/api_client.rs +++ b/src-tauri/src/api_client.rs @@ -818,7 +818,7 @@ impl ApiClient { Ok(filtered_releases) } - /// Check if a Brave release has compatible assets for the given platform and architecture + /// Check if a Camoufox release has compatible assets for the given platform and architecture fn has_compatible_camoufox_asset( &self, assets: &[crate::browser::GithubAsset], @@ -835,9 +835,9 @@ impl ApiClient { _ => return false, }; - // Look for assets matching the pattern: camoufox-{version}-{release}-{os}.{arch}.zip - // Use ends_with for precise matching to avoid false positives - let pattern = format!(".{os_name}.{arch_name}.zip"); + // Look for assets matching the pattern: camoufox-{version}-beta.{number}-{os}.{arch}.zip + // The separator before OS is a dash, e.g., camoufox-135.0.1-beta.24-lin.x86_64.zip + let pattern = format!("-{os_name}.{arch_name}.zip"); assets.iter().any(|asset| { let name = asset.name.to_lowercase(); name.starts_with("camoufox-") && name.ends_with(&pattern) diff --git a/src-tauri/src/downloader.rs b/src-tauri/src/downloader.rs index 7418036..aafc559 100644 --- a/src-tauri/src/downloader.rs +++ b/src-tauri/src/downloader.rs @@ -310,7 +310,8 @@ impl Downloader { os: &str, arch: &str, ) -> Option { - // Camoufox asset naming pattern: camoufox-{version}-{release}-{os}.{arch}.zip + // Camoufox asset naming pattern: camoufox-{version}-beta.{number}-{os}.{arch}.zip + // Example: camoufox-135.0.1-beta.24-lin.x86_64.zip let (os_name, arch_name) = match (os, arch) { ("windows", "x64") => ("win", "x86_64"), ("windows", "arm64") => ("win", "arm64"), @@ -322,7 +323,8 @@ impl Downloader { }; // Use ends_with for precise matching to avoid false positives - let pattern = format!(".{os_name}.{arch_name}.zip"); + // The separator before OS is a dash: -lin.x86_64.zip, -mac.arm64.zip, etc. + let pattern = format!("-{os_name}.{arch_name}.zip"); let asset = assets.iter().find(|asset| { let name = asset.name.to_lowercase(); name.starts_with("camoufox-") && name.ends_with(&pattern) diff --git a/src/components/create-profile-dialog.tsx b/src/components/create-profile-dialog.tsx index 5965e14..0b6e573 100644 --- a/src/components/create-profile-dialog.tsx +++ b/src/components/create-profile-dialog.tsx @@ -142,6 +142,10 @@ export function CreateProfileDialog({ const [showProxyForm, setShowProxyForm] = useState(false); const [isCreating, setIsCreating] = useState(false); const [releaseTypes, setReleaseTypes] = useState(); + const [isLoadingReleaseTypes, setIsLoadingReleaseTypes] = useState(false); + const [releaseTypesError, setReleaseTypesError] = useState( + null, + ); const loadingBrowserRef = useRef(null); // Use the browser download hook @@ -179,6 +183,8 @@ export function CreateProfileDialog({ async (browser: string) => { // Set loading state loadingBrowserRef.current = browser; + setIsLoadingReleaseTypes(true); + setReleaseTypesError(null); try { const rawReleaseTypes = await invoke( @@ -207,6 +213,7 @@ export function CreateProfileDialog({ filtered.stable = rawReleaseTypes.stable; setReleaseTypes(filtered); } + setReleaseTypesError(null); } } catch (error) { console.error(`Failed to load release types for ${browser}:`, error); @@ -223,17 +230,29 @@ export function CreateProfileDialog({ fallback.stable = latest; } setReleaseTypes(fallback); + setReleaseTypesError(null); + } else if (loadingBrowserRef.current === browser) { + // No downloaded versions and API failed - show error + setReleaseTypesError( + "Failed to fetch browser versions. Please check your internet connection and try again.", + ); } } catch (e) { console.error( `Failed to load downloaded versions for ${browser}:`, e, ); + if (loadingBrowserRef.current === browser) { + setReleaseTypesError( + "Failed to fetch browser versions. Please check your internet connection and try again.", + ); + } } } finally { // Clear loading state only if we're still loading this browser if (loadingBrowserRef.current === browser) { loadingBrowserRef.current = null; + setIsLoadingReleaseTypes(false); } } }, @@ -377,6 +396,8 @@ export function CreateProfileDialog({ setSelectedBrowser(null); setSelectedProxyId(undefined); setReleaseTypes({}); + setIsLoadingReleaseTypes(false); + setReleaseTypesError(null); setCamoufoxConfig({ geoip: true, // Reset to automatic geoip os: getCurrentOS(), // Reset to current OS @@ -553,7 +574,34 @@ export function CreateProfileDialog({ // Camoufox Configuration
{/* Camoufox Download Status */} - {!isBrowserCurrentlyDownloading("camoufox") && + {isLoadingReleaseTypes && ( +
+
+

+ Fetching available versions... +

+
+ )} + {!isLoadingReleaseTypes && releaseTypesError && ( +
+

+ {releaseTypesError} +

+ + selectedBrowser && + loadReleaseTypes(selectedBrowser) + } + size="sm" + variant="outline" + > + Retry + +
+ )} + {!isLoadingReleaseTypes && + !releaseTypesError && + !isBrowserCurrentlyDownloading("camoufox") && !isBrowserVersionAvailable("camoufox") && getBestAvailableVersion("camoufox") && (
@@ -580,7 +628,9 @@ export function CreateProfileDialog({
)} - {!isBrowserCurrentlyDownloading("camoufox") && + {!isLoadingReleaseTypes && + !releaseTypesError && + !isBrowserCurrentlyDownloading("camoufox") && isBrowserVersionAvailable("camoufox") && (
{(() => { @@ -607,13 +657,41 @@ export function CreateProfileDialog({ />
) : ( - // Regular Browser Configuration + // Regular Browser Configuration (should not happen in anti-detect tab)
{selectedBrowser && (
- {!isBrowserCurrentlyDownloading( - selectedBrowser, - ) && + {isLoadingReleaseTypes && ( +
+
+

+ Fetching available versions... +

+
+ )} + {!isLoadingReleaseTypes && + releaseTypesError && ( +
+

+ {releaseTypesError} +

+ + selectedBrowser && + loadReleaseTypes(selectedBrowser) + } + size="sm" + variant="outline" + > + Retry + +
+ )} + {!isLoadingReleaseTypes && + !releaseTypesError && + !isBrowserCurrentlyDownloading( + selectedBrowser, + ) && !isBrowserVersionAvailable(selectedBrowser) && getBestAvailableVersion(selectedBrowser) && (
@@ -643,9 +721,11 @@ export function CreateProfileDialog({
)} - {!isBrowserCurrentlyDownloading( - selectedBrowser, - ) && + {!isLoadingReleaseTypes && + !releaseTypesError && + !isBrowserCurrentlyDownloading( + selectedBrowser, + ) && isBrowserVersionAvailable( selectedBrowser, ) && ( @@ -739,9 +819,36 @@ export function CreateProfileDialog({
{selectedBrowser && (
- {!isBrowserCurrentlyDownloading( - selectedBrowser, - ) && + {isLoadingReleaseTypes && ( +
+
+

+ Fetching available versions... +

+
+ )} + {!isLoadingReleaseTypes && releaseTypesError && ( +
+

+ {releaseTypesError} +

+ + selectedBrowser && + loadReleaseTypes(selectedBrowser) + } + size="sm" + variant="outline" + > + Retry + +
+ )} + {!isLoadingReleaseTypes && + !releaseTypesError && + !isBrowserCurrentlyDownloading( + selectedBrowser, + ) && !isBrowserVersionAvailable(selectedBrowser) && getBestAvailableVersion(selectedBrowser) && (
@@ -771,9 +878,11 @@ export function CreateProfileDialog({
)} - {!isBrowserCurrentlyDownloading( - selectedBrowser, - ) && + {!isLoadingReleaseTypes && + !releaseTypesError && + !isBrowserCurrentlyDownloading( + selectedBrowser, + ) && isBrowserVersionAvailable(selectedBrowser) && (
{(() => {