diff --git a/src/App.tsx b/src/App.tsx index abb8128..d46e48a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,7 +4,7 @@ import { AppContext } from "@/providers/appContextProvider"; import { useEffect, useRef, useState } from "react"; import { arch, exeExtension } from "@tauri-apps/plugin-os"; import { downloadDir, join, resourceDir, tempDir } from "@tauri-apps/api/path"; -import { useBasePathsStore, useCurrentVideoMetadataStore, useDownloaderPageStatesStore, useDownloadStatesStore, useKvPairsStatesStore, useSettingsPageStatesStore } from "@/services/store"; +import { useBasePathsStore, useCurrentVideoMetadataStore, useDownloaderPageStatesStore, useDownloadStatesStore, useEnvironmentStore, useKvPairsStatesStore, useSettingsPageStatesStore } from "@/services/store"; import { isObjEmpty} from "@/utils"; import { Command } from "@tauri-apps/plugin-shell"; import { useUpdateDownloadStatus } from "@/services/mutations"; @@ -40,6 +40,10 @@ export default function App({ children }: { children: React.ReactNode }) { const setDownloadStates = useDownloadStatesStore((state) => state.setDownloadStates); const setPath = useBasePathsStore((state) => state.setPath); + const setIsFlatpak = useEnvironmentStore((state) => state.setIsFlatpak); + const setIsAppimage = useEnvironmentStore((state) => state.setIsAppimage); + const setAppDirPath = useEnvironmentStore((state) => state.setAppDirPath); + const setIsUsingDefaultSettings = useSettingsPageStatesStore((state) => state.setIsUsingDefaultSettings); const setSettingsKey = useSettingsPageStatesStore((state) => state.setSettingsKey); const appVersion = useSettingsPageStatesStore(state => state.appVersion); @@ -122,6 +126,26 @@ export default function App({ children }: { children: React.ReactNode }) { }; }, [stopPotServer]); + // Detect sandbox environments + useEffect(() => { + const detectEnvironment = async () => { + try { + const isFlatpak = await invoke('is_flatpak'); + const appimagePath = await invoke('get_appimage_path'); + console.log('Environment detection results:', { isFlatpak, appimagePath }); + + if (isFlatpak) setIsFlatpak(true); + if (appimagePath) { + setIsAppimage(true); + setAppDirPath(appimagePath); + } + } catch (e) { + console.error('Failed to detect environment:', e); + } + } + detectEnvironment(); + }, [setIsFlatpak, setIsAppimage, setAppDirPath]); + // Listen for websocket messages useEffect(() => { const unlisten = listen('websocket-message', (event) => { diff --git a/src/components/pages/library/completedDownloads.tsx b/src/components/pages/library/completedDownloads.tsx index 5c9bfd3..5ebfe3c 100644 --- a/src/components/pages/library/completedDownloads.tsx +++ b/src/components/pages/library/completedDownloads.tsx @@ -4,7 +4,7 @@ import { AspectRatio } from "@/components/ui/aspect-ratio"; import { Button } from "@/components/ui/button"; import { Separator } from "@/components/ui/separator"; import { toast } from "sonner"; -import { useCurrentVideoMetadataStore, useDownloadActionStatesStore, useLibraryPageStatesStore } from "@/services/store"; +import { useCurrentVideoMetadataStore, useDownloadActionStatesStore, useEnvironmentStore, useLibraryPageStatesStore } from "@/services/store"; import { formatBitrate, formatCodec, formatDurationString, formatFileSize, paginate } from "@/utils"; import { ArrowUpRightIcon, AudioLines, CircleArrowDown, Clock, File, FileAudio2, FileQuestion, FileVideo2, FolderInput, ListVideo, Music, Play, Search, Trash2, Video } from "lucide-react"; import { invoke } from "@tauri-apps/api/core"; @@ -33,6 +33,8 @@ export function CompletedDownload({ state }: CompletedDownloadProps) { const downloadActions = useDownloadActionStatesStore(state => state.downloadActions); const setIsDeleteFileChecked = useDownloadActionStatesStore(state => state.setIsDeleteFileChecked); + const isFlatpak = useEnvironmentStore(state => state.isFlatpak); + const queryClient = useQueryClient(); const downloadStateDeleter = useDeleteDownloadState(); const navigate = useNavigate(); @@ -276,10 +278,12 @@ export function CompletedDownload({ state }: CompletedDownloadProps) { Open - + {!isFlatpak && ( + + )} +
+

Health Check

+

Ensure everything is working fine

+ {isFlatpak ? ( + + + Flatpak Sandbox Detected! + + It looks like you are running NeoDLP in a Flatpak sandbox. Some features like changing download folder, revealing completed downloads in explorer and automatic yt-dlp updates are not available in Flatpak due to sandbox restrictions. To use these features, please install the native build (DEB, RPM or AUR) of NeoDLP. + + + ) : isAppimage ? ( + + + Appimage Environment Detected! + + Looks like you are using NeoDLP Appimage. NeoDLP's browser integration features are not available on Appimage environment due to it's limitations. To use NeoDLP's browser integration features please install the native build (DEB, RPM or AUR) of NeoDLP. + + + ) : ( + + + All Set! Cheers :) + + NeoDLP is running as normal without any limitations! You should be able to use all the features of NeoDLP without any issues. If you face any problem, feel free to report it to us. + + + )} +

Bug Report

Noticed any bug or inconsistencies? Report it to help us improve

@@ -1869,6 +1904,8 @@ function AppInfoSettings() { } export function ApplicationSettings() { + const isFlatpak = useEnvironmentStore(state => state.isFlatpak); + const activeSubAppTab = useSettingsPageStatesStore(state => state.activeSubAppTab); const setActiveSubAppTab = useSettingsPageStatesStore(state => state.setActiveSubAppTab); @@ -1926,12 +1963,14 @@ export function ApplicationSettings() { saveSettingsKey('ytdlp_auto_update', checked)} />
- - - - + + + + + -

* These links opens with coresponding browsers only (except on flatpak). Make sure the browser is installed before clicking the link

+

* These links opens with coresponding browsers only. Make sure the browser is installed before clicking the link

); } diff --git a/src/components/sidebar.tsx b/src/components/sidebar.tsx index 7f9e603..4b14822 100644 --- a/src/components/sidebar.tsx +++ b/src/components/sidebar.tsx @@ -46,7 +46,7 @@ export function AppSidebar() { ]; useEffect(() => { - let timeout: NodeJS.Timeout; + let timeout: ReturnType; if (open) { timeout = setTimeout(() => { setShowBadge(true); diff --git a/src/services/store.ts b/src/services/store.ts index cb33561..277a87c 100644 --- a/src/services/store.ts +++ b/src/services/store.ts @@ -1,4 +1,4 @@ -import { BasePathsStore, CurrentVideoMetadataStore, DownloadActionStatesStore, DownloaderPageStatesStore, DownloadStatesStore, KvPairsStatesStore, LibraryPageStatesStore, LogsStore, SettingsPageStatesStore } from '@/types/store'; +import { BasePathsStore, CurrentVideoMetadataStore, DownloadActionStatesStore, DownloaderPageStatesStore, DownloadStatesStore, EnvironmentStore, KvPairsStatesStore, LibraryPageStatesStore, LogsStore, SettingsPageStatesStore } from '@/types/store'; import { create } from 'zustand'; export const useBasePathsStore = create((set) => ({ @@ -352,3 +352,12 @@ export const useLogsStore = create((set) => ({ addLog: (log) => set((state) => ({ logs: [...state.logs, log] })), clearLogs: () => set(() => ({ logs: [] })) })); + +export const useEnvironmentStore = create((set) => ({ + isFlatpak: false, + isAppimage: false, + appDirPath: null, + setIsFlatpak: (isFlatpak) => set(() => ({ isFlatpak })), + setIsAppimage: (isAppimage) => set(() => ({ isAppimage })), + setAppDirPath: (path) => set(() => ({ appDirPath: path })) +})); diff --git a/src/types/store.ts b/src/types/store.ts index 5643eae..524be4a 100644 --- a/src/types/store.ts +++ b/src/types/store.ts @@ -152,3 +152,12 @@ export interface LogsStore { addLog: (log: Log) => void; clearLogs: () => void; } + +export interface EnvironmentStore { + isFlatpak: boolean; + isAppimage: boolean; + appDirPath: string | null; + setIsFlatpak: (isFlatpak: boolean) => void; + setIsAppimage: (isAppimage: boolean) => void; + setAppDirPath: (path: string) => void; +}