From 6bf52dd27e950138a04987ad48ef1c1a518a8fc3 Mon Sep 17 00:00:00 2001 From: neosubhamoy Date: Thu, 29 Aug 2024 13:13:32 +0530 Subject: [PATCH] (feat): now pytubepp helper can install required packages via install buttons using winget and pip --- package-lock.json | 10 ++++ package.json | 1 + src-tauri/pytubepp-helper-msghost.json | 2 +- src-tauri/src/main.rs | 35 ++++++++++++++ src-tauri/tauri.conf.json | 19 +++++--- src/App.tsx | 65 +++++++++++++++++++++----- src/components/ui/alert.tsx | 59 +++++++++++++++++++++++ src/lib/utils.ts | 19 +++++++- src/types.ts | 12 +++-- 9 files changed, 196 insertions(+), 26 deletions(-) create mode 100644 src/components/ui/alert.tsx diff --git a/package-lock.json b/package-lock.json index 593a906..ed79c97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "dotenv": "^16.4.5", + "lucide-react": "^0.436.0", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwind-merge": "^2.5.2", @@ -2141,6 +2142,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.436.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.436.0.tgz", + "integrity": "sha512-N292bIxoqm1aObAg0MzFtvhYwgQE6qnIOWx/GLj5ONgcTPH6N0fD9bVq/GfdeC9ZORBXozt/XeEKDpiB3x3vlQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", diff --git a/package.json b/package.json index 2f4943b..95fcc94 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "dotenv": "^16.4.5", + "lucide-react": "^0.436.0", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwind-merge": "^2.5.2", diff --git a/src-tauri/pytubepp-helper-msghost.json b/src-tauri/pytubepp-helper-msghost.json index 944b806..0b34d09 100644 --- a/src-tauri/pytubepp-helper-msghost.json +++ b/src-tauri/pytubepp-helper-msghost.json @@ -3,5 +3,5 @@ "description": "A helper app for pytubepp-extention to communicate with pytubepp-cli", "path": "pytubepp-helper-msghost.exe", "type": "stdio", - "allowed_origins": ["chrome-extension://adebedkaedobamilbbobbajepnnkkfcg/"] + "allowed_origins": ["chrome-extension://adebedkaedobamilbbobbajepnnkkfcg/", "chrome-extension://mmhhbpdhkogpcieblpdilflfoimajepp"] } \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 750ee60..b5d0540 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -83,6 +83,40 @@ fn fetch_video_info(url: String) { } } +#[tauri::command] +fn install_program(installer: String ,program: String) { + #[cfg(target_os = "windows")] + { + let command = format!("{} install {}", &installer, &program); + Command::new("cmd") + .args(["/k", command.as_str()]) + .spawn() + .unwrap(); + } + + #[cfg(target_os = "linux")] + { + let command = format!("{} install {}", &installer, &program); + Command::new("gnome-terminal") + .args(["--", command.as_str()]) + .spawn() + .unwrap(); + } + + #[cfg(target_os = "macos")] + { + let command = format!("{} install {}", &installer, &program); + Command::new("osascript") + .arg("-e") + .arg(format!( + "tell app \"Terminal\" to activate do script \"{}\"", + command + )) + .spawn() + .unwrap(); + } +} + #[tauri::command] fn download_stream(url: String, stream: String) { #[cfg(target_os = "windows")] @@ -173,6 +207,7 @@ async fn main() { // handle_websocket_message, send_to_extension, fetch_video_info, + install_program, download_stream, receive_frontend_response ]) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index f2816c6..485dbd9 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -19,13 +19,18 @@ "open": true, "scope": [ { - "name": "is-pytubepp-installed", - "cmd": "pytubepp", + "name": "is-winget-installed", + "cmd": "winget", "args": ["--version"] }, { - "name": "is-pytubefix-installed", - "cmd": "pytubefix", + "name": "is-python-installed", + "cmd": "python", + "args": ["--version"] + }, + { + "name": "is-pip-installed", + "cmd": "pip", "args": ["--version"] }, { @@ -34,8 +39,8 @@ "args": ["-version"] }, { - "name": "is-python-installed", - "cmd": "python", + "name": "is-pytubepp-installed", + "cmd": "pytubepp", "args": ["--version"] }, { @@ -75,7 +80,7 @@ { "title": "PytubePP Helper", "width": 500, - "height": 300 + "height": 320 } ], "security": { diff --git a/src/App.tsx b/src/App.tsx index 396b7d7..d11d49c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,8 +5,10 @@ import { listen } from '@tauri-apps/api/event'; import { appWindow } from '@tauri-apps/api/window'; import { ThemeProvider } from "@/components/theme-provider"; import { Button } from "@/components/ui/button"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" import { InstalledPrograms, WebSocketMessage, } from "./types"; -import { extract_version, is_installed, sendStreamInfo } from "./lib/utils"; +import { compareVersions, extract_version, is_installed, sendStreamInfo } from "./lib/utils"; +import { CircleCheck, TriangleAlert, CircleAlert } from 'lucide-react'; function App() { useEffect(() => { @@ -19,15 +21,19 @@ function App() { }, []); const [installedPrograms, setInstalledPrograms] = useState({ + winget: { + installed: false, + version: null, + }, python: { installed: false, version: null, }, - ffmpeg: { + pip: { installed: false, version: null, }, - pytubefix: { + ffmpeg: { installed: false, version: null, }, @@ -66,6 +72,15 @@ function App() { }, []); function check_all_programs() { + is_installed('winget', '--version').then((result) => { + setInstalledPrograms((prevState) => ({ + ...prevState, + winget: { + installed: result.installed, + version: result.output ? extract_version(result.output) : null, + } + })); + }); is_installed('python', '--version').then((result) => { setInstalledPrograms((prevState) => ({ ...prevState, @@ -75,19 +90,19 @@ function App() { } })); }); - is_installed('ffmpeg', '-version').then((result) => { + is_installed('pip', '--version').then((result) => { setInstalledPrograms((prevState) => ({ ...prevState, - ffmpeg: { + pip: { installed: result.installed, version: result.output ? extract_version(result.output) : null, } })); }); - is_installed('pytubefix', '--version').then((result) => { + is_installed('ffmpeg', '-version').then((result) => { setInstalledPrograms((prevState) => ({ ...prevState, - pytubefix: { + ffmpeg: { installed: result.installed, version: result.output ? extract_version(result.output) : null, } @@ -114,13 +129,39 @@ function App() {

PytubePP Helper

- +
-

Python: {installedPrograms.python.installed ? 'installed' : 'not installed'} {installedPrograms.python.version ? `(${installedPrograms.python.version})` : ''}

-

FFmpeg: {installedPrograms.ffmpeg.installed ? 'installed' : 'not installed'} {installedPrograms.ffmpeg.version ? `(${installedPrograms.ffmpeg.version})` : ''}

-

pytubefix: {installedPrograms.pytubefix.installed ? 'installed' : 'not installed'} {installedPrograms.pytubefix.version ? `(${installedPrograms.pytubefix.version})` : ''}

-

pytubepp: {installedPrograms.pytubepp.installed ? 'installed' : 'not installed'} {installedPrograms.pytubepp.version ? `(${installedPrograms.pytubepp.version})` : ''}

+
+

Python: {installedPrograms.python.installed ? 'installed' : 'not installed'} {installedPrograms.python.version ? `(${installedPrograms.python.version})` : ''}

+ {installedPrograms.python.installed ? installedPrograms.python.version ? compareVersions(installedPrograms.python.version, '3.8') < 0 ? : : installedPrograms.winget.installed ? : : null} +
+
+

FFmpeg: {installedPrograms.ffmpeg.installed ? 'installed' : 'not installed'} {installedPrograms.ffmpeg.version ? `(${installedPrograms.ffmpeg.version})` : ''}

+ {installedPrograms.ffmpeg.installed ? : installedPrograms.winget.installed ? : null} +
+
+

PytubePP: {installedPrograms.pytubepp.installed ? 'installed' : 'not installed'} {installedPrograms.pytubepp.version ? `(${installedPrograms.pytubepp.version})` : ''}

+ {installedPrograms.pytubepp.installed ? : installedPrograms.pip.installed ? : null} +
+ {(!installedPrograms.winget.installed && (!installedPrograms.python.installed || !installedPrograms.ffmpeg.installed)) ? + + + WinGet Not Found + + WinGet is required to install necessary packages. Please install it manually from here. + + + : null} + {(installedPrograms.python.installed && installedPrograms.ffmpeg.installed && installedPrograms.pytubepp.installed) ? + + + Ready + + Everything looks ok! You can close this window now. Make sure it's always running in the background. + + + : null}
diff --git a/src/components/ui/alert.tsx b/src/components/ui/alert.tsx new file mode 100644 index 0000000..5afd41d --- /dev/null +++ b/src/components/ui/alert.tsx @@ -0,0 +1,59 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const alertVariants = cva( + "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7", + { + variants: { + variant: { + default: "bg-background text-foreground", + destructive: + "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +const Alert = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & VariantProps +>(({ className, variant, ...props }, ref) => ( +
+)) +Alert.displayName = "Alert" + +const AlertTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +AlertTitle.displayName = "AlertTitle" + +const AlertDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +AlertDescription.displayName = "AlertDescription" + +export { Alert, AlertTitle, AlertDescription } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index b709305..7757ce1 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -59,7 +59,10 @@ export function extract_version(output: string): string | null { /ffmpeg version (\d+\.\d+)/, // Pattern for ffmpeg /Python (\d+\.\d+\.\d+)/, // Pattern for Python /pytubefix (\d+\.\d+\.\d+)/, // Pattern for pytubefix - /pytubepp (\d+\.\d+\.\d+)/ // Pattern for pytubepp + /pytubepp (\d+\.\d+\.\d+)/, // Pattern for pytubepp + /v(\d+\.\d+\.\d+)/, // Pattern for winget + /pip (\d+\.\d+)/, // Pattern for pip + ]; for (const pattern of versionPatterns) { const match = output.match(pattern); @@ -94,4 +97,16 @@ export async function sendStreamInfo(url: string) { }; fetchData(); -} \ No newline at end of file +} + +export function compareVersions (v1: string, v2: string) { + const parts1 = v1.split('.').map(Number); + const parts2 = v2.split('.').map(Number); + for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { + const part1 = parts1[i] || 0; + const part2 = parts2[i] || 0; + if (part1 > part2) return 1; + if (part1 < part2) return -1; + } + return 0; +}; \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index d2a01ab..43dbcd7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,16 +1,20 @@ export interface InstalledPrograms { + winget: { + installed: boolean; + version: string | null; + }; python: { installed: boolean; version: string | null; }; + pip: { + installed: boolean; + version: string | null; + }; ffmpeg: { installed: boolean; version: string | null; }; - pytubefix: { - installed: boolean - version: string | null; - }; pytubepp: { installed: boolean; version: string | null;