mirror of
https://github.com/neosubhamoy/pytubepp-helper.git
synced 2026-02-04 11:22:22 +05:30
(feat): added support for common rhel (rpm) based linux distros
This commit is contained in:
@@ -18,11 +18,21 @@
|
||||
"sidecar": true,
|
||||
"open": true,
|
||||
"scope": [
|
||||
{
|
||||
"name": "detect-distro",
|
||||
"cmd": "grep",
|
||||
"args": ["^ID=", "/etc/os-release"]
|
||||
},
|
||||
{
|
||||
"name": "is-apt-installed",
|
||||
"cmd": "apt",
|
||||
"args": ["--version"]
|
||||
},
|
||||
{
|
||||
"name": "is-dnf-installed",
|
||||
"cmd": "dnf",
|
||||
"args": ["--version"]
|
||||
},
|
||||
{
|
||||
"name": "is-python-installed",
|
||||
"cmd": "python3",
|
||||
@@ -99,6 +109,20 @@
|
||||
"/usr/bin/pytubepp-helper-autostart": "./target/release/pytubepp-helper-autostart",
|
||||
"/etc/xdg/autostart/pytubepp-helper-autostart.desktop": "./autostart/pytubepp-helper-autostart.desktop"
|
||||
}
|
||||
},
|
||||
"rpm": {
|
||||
"epoch": 0,
|
||||
"release": "1",
|
||||
"license": "MIT",
|
||||
"depends": ["python3-pip", "ffmpeg-free"],
|
||||
"files": {
|
||||
"/etc/opt/chrome/native-messaging-hosts/com.neosubhamoy.pytubepp.helper.json": "./msghost-manifest/chrome/com.neosubhamoy.pytubepp.helper.json",
|
||||
"/etc/chromium/native-messaging-hosts/com.neosubhamoy.pytubepp.helper.json": "./msghost-manifest/chrome/com.neosubhamoy.pytubepp.helper.json",
|
||||
"/usr/lib/mozilla/native-messaging-hosts/com.neosubhamoy.pytubepp.helper.json": "./msghost-manifest/firefox/com.neosubhamoy.pytubepp.helper.json",
|
||||
"/usr/bin/pytubepp-helper-msghost": "./target/release/pytubepp-helper-msghost",
|
||||
"/usr/bin/pytubepp-helper-autostart": "./target/release/pytubepp-helper-autostart",
|
||||
"/etc/xdg/autostart/pytubepp-helper-autostart.desktop": "./autostart/pytubepp-helper-autostart.desktop"
|
||||
}
|
||||
}
|
||||
},
|
||||
"systemTray": {
|
||||
|
||||
@@ -5,9 +5,9 @@ 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 { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { InstalledPrograms, WebSocketMessage, } from "./types";
|
||||
import { compareVersions, extract_version, is_installed, sendStreamInfo } from "./lib/utils";
|
||||
import { compareVersions, extractVersion, isInstalled, sendStreamInfo, extractDistroId, detectDistro, detectDistroBase } from "./lib/utils";
|
||||
import { CircleCheck, TriangleAlert, CircleAlert } from 'lucide-react';
|
||||
|
||||
function App() {
|
||||
@@ -19,12 +19,18 @@ function App() {
|
||||
|
||||
appWindow.onCloseRequested(handleCloseRequested);
|
||||
}, []);
|
||||
|
||||
|
||||
const [distroId, setDistroId] = useState<string | null>(null)
|
||||
const [distroBase, setDistroBase] = useState<string | null>(null)
|
||||
const [installedPrograms, setInstalledPrograms] = useState<InstalledPrograms>({
|
||||
apt: {
|
||||
installed: false,
|
||||
version: null,
|
||||
},
|
||||
dnf: {
|
||||
installed: false,
|
||||
version: null,
|
||||
},
|
||||
python: {
|
||||
installed: false,
|
||||
version: null,
|
||||
@@ -71,56 +77,71 @@ function App() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
function check_all_programs() {
|
||||
is_installed('apt', '--version').then((result) => {
|
||||
function checkAllPrograms() {
|
||||
isInstalled('apt', '--version').then((result) => {
|
||||
setInstalledPrograms((prevState) => ({
|
||||
...prevState,
|
||||
apt: {
|
||||
installed: result.installed,
|
||||
version: result.output ? extract_version(result.output) : null,
|
||||
version: result.output ? extractVersion(result.output) : null,
|
||||
}
|
||||
}));
|
||||
});
|
||||
is_installed('python', '--version').then((result) => {
|
||||
isInstalled('dnf', '--version').then((result) => {
|
||||
setInstalledPrograms((prevState) => ({
|
||||
...prevState,
|
||||
dnf: {
|
||||
installed: result.installed,
|
||||
version: result.output ? extractVersion(result.output) : null,
|
||||
}
|
||||
}));
|
||||
});
|
||||
isInstalled('python', '--version').then((result) => {
|
||||
setInstalledPrograms((prevState) => ({
|
||||
...prevState,
|
||||
python: {
|
||||
installed: result.installed,
|
||||
version: result.output ? extract_version(result.output) : null,
|
||||
version: result.output ? extractVersion(result.output) : null,
|
||||
}
|
||||
}));
|
||||
});
|
||||
is_installed('pip', '--version').then((result) => {
|
||||
isInstalled('pip', '--version').then((result) => {
|
||||
setInstalledPrograms((prevState) => ({
|
||||
...prevState,
|
||||
pip: {
|
||||
installed: result.installed,
|
||||
version: result.output ? extract_version(result.output) : null,
|
||||
version: result.output ? extractVersion(result.output) : null,
|
||||
}
|
||||
}));
|
||||
});
|
||||
is_installed('ffmpeg', '-version').then((result) => {
|
||||
isInstalled('ffmpeg', '-version').then((result) => {
|
||||
setInstalledPrograms((prevState) => ({
|
||||
...prevState,
|
||||
ffmpeg: {
|
||||
installed: result.installed,
|
||||
version: result.output ? extract_version(result.output) : null,
|
||||
version: result.output ? extractVersion(result.output) : null,
|
||||
}
|
||||
}));
|
||||
});
|
||||
is_installed('pytubepp', '--version').then((result) => {
|
||||
isInstalled('pytubepp', '--version').then((result) => {
|
||||
setInstalledPrograms((prevState) => ({
|
||||
...prevState,
|
||||
pytubepp: {
|
||||
installed: result.installed,
|
||||
version: result.output ? extract_version(result.output) : null,
|
||||
version: result.output ? extractVersion(result.output) : null,
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
check_all_programs();
|
||||
checkAllPrograms();
|
||||
detectDistro().then((result) => {
|
||||
if(result) {
|
||||
setDistroId(extractDistroId(result))
|
||||
setDistroBase(detectDistroBase(extractDistroId(result)))
|
||||
}
|
||||
})
|
||||
}
|
||||
, []);
|
||||
|
||||
@@ -129,8 +150,9 @@ function App() {
|
||||
<div className="container">
|
||||
<div className="topbar flex justify-between items-center mt-5 mx-3">
|
||||
<h1 className="text-xl font-bold">PytubePP Helper</h1>
|
||||
<Button size="sm" onClick={check_all_programs}>Refresh</Button>
|
||||
<Button size="sm" onClick={checkAllPrograms}>Refresh</Button>
|
||||
</div>
|
||||
{ distroId && distroBase && distroBase === 'debian' ?
|
||||
<div className="programstats mt-5 mx-3">
|
||||
<div className="programitem flex items-center justify-between">
|
||||
<p><b>Python:</b> {installedPrograms.python.installed ? 'installed' : 'not installed'} {installedPrograms.python.version ? `(${installedPrograms.python.version})` : ''}</p>
|
||||
@@ -172,6 +194,59 @@ function App() {
|
||||
</Alert>
|
||||
: null}
|
||||
</div>
|
||||
: distroId && distroBase && distroBase === 'rhel' ?
|
||||
<div className="programstats mt-5 mx-3">
|
||||
<div className="programitem flex items-center justify-between">
|
||||
<p><b>Python:</b> {installedPrograms.python.installed ? 'installed' : 'not installed'} {installedPrograms.python.version ? `(${installedPrograms.python.version})` : ''}</p>
|
||||
{installedPrograms.python.installed ? installedPrograms.python.version ? compareVersions(installedPrograms.python.version, '3.8') < 0 ? <TriangleAlert className="w-5 h-5 my-2 text-orange-400"/> : <CircleCheck className="w-5 h-5 my-2 text-green-400"/> : installedPrograms.dnf.installed ? <Button variant="link" className="text-blue-600 px-0" onClick={async () => { await invoke('install_program', {icommand: 'sudo dnf install python3.12 -y'})}}>install</Button> : <TriangleAlert className="w-5 h-5 my-2 text-orange-400"/> : null}
|
||||
</div>
|
||||
<div className="programitem flex items-center justify-between">
|
||||
<p><b>FFmpeg:</b> {installedPrograms.ffmpeg.installed ? 'installed' : 'not installed'} {installedPrograms.ffmpeg.version ? `(${installedPrograms.ffmpeg.version})` : ''}</p>
|
||||
{installedPrograms.ffmpeg.installed ? <CircleCheck className="w-5 h-5 my-2 text-green-400"/> : installedPrograms.dnf.installed ? <Button variant="link" className="text-blue-600 px-0" onClick={async () => { await invoke('install_program', {icommand: 'sudo dnf install ffmpeg-free -y'})}}>install</Button> : null}
|
||||
</div>
|
||||
<div className="programitem flex items-center justify-between">
|
||||
<p><b>PytubePP:</b> {installedPrograms.pytubepp.installed ? 'installed' : 'not installed'} {installedPrograms.pytubepp.version ? `(${installedPrograms.pytubepp.version})` : ''}</p>
|
||||
{installedPrograms.pytubepp.installed ? <CircleCheck className="w-5 h-5 my-2 text-green-400"/> : installedPrograms.pip.installed ? <Button variant="link" className="text-blue-600 px-0" onClick={async () => { await invoke('install_program', {icommand: 'pip install pytubepp'})}}>install</Button> : null}
|
||||
</div>
|
||||
{(!installedPrograms.dnf.installed && (!installedPrograms.python.installed || !installedPrograms.ffmpeg.installed)) ?
|
||||
<Alert className="mt-5" variant="destructive">
|
||||
<CircleAlert className="h-5 w-5" />
|
||||
<AlertTitle>DNF Not Found</AlertTitle>
|
||||
<AlertDescription>
|
||||
DNF is required to install necessary debian packages. Please install it manually for your distro.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
: null}
|
||||
{(!installedPrograms.pip.installed && !installedPrograms.pytubepp.installed) ?
|
||||
<Alert className="mt-5" variant="destructive">
|
||||
<CircleAlert className="h-5 w-5" />
|
||||
<AlertTitle>PIP Not Found</AlertTitle>
|
||||
<AlertDescription>
|
||||
PIP is required to install necessary python packages. Please install it now to continue: <Button variant="link" className="text-blue-600 p-0" onClick={async () => { await invoke('install_program', {icommand: 'sudo dnf install python3-pip -y'})}}>install</Button>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
: null}
|
||||
{(installedPrograms.python.installed && installedPrograms.ffmpeg.installed && installedPrograms.pytubepp.installed) ?
|
||||
<Alert className="mt-5">
|
||||
<CircleCheck className="h-5 w-5" />
|
||||
<AlertTitle>Ready</AlertTitle>
|
||||
<AlertDescription>
|
||||
Everything looks ok! You can close this window now. Make sure it's always running in the background.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
: null}
|
||||
</div>
|
||||
:
|
||||
<div className="programstats mt-5 mx-3">
|
||||
<Alert className="mt-5" variant="destructive">
|
||||
<CircleAlert className="h-5 w-5" />
|
||||
<AlertTitle>Unsupported Distro</AlertTitle>
|
||||
<AlertDescription>
|
||||
Sorry, your linux distro is currently not supported. If you think this is just a mistake or you want to request us to add support for your distro you can create a github issue <a className="underline" href="https://github.com/neosubhamoy/pytubepp-helper/issues" target="_blank">here</a>.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Command } from '@tauri-apps/api/shell';
|
||||
import { Stream } from "@/types";
|
||||
import { invoke } from "@tauri-apps/api";
|
||||
|
||||
export function extract_xml(input: string): string[] {
|
||||
export function extractXml(input: string): string[] {
|
||||
const regex = /<Stream: [^>]+>/g;
|
||||
const matches = input.match(regex);
|
||||
return matches ? matches : [];
|
||||
@@ -27,7 +27,7 @@ function parseAttributes(attributesString: string): Partial<Stream> {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
export function convert_xml_to_json(xmlStrings: string[]): Stream[] {
|
||||
export function convertXmlToJson(xmlStrings: string[]): Stream[] {
|
||||
return xmlStrings
|
||||
.map(xmlString => {
|
||||
const attributesString = xmlString.replace('<Stream: ', '').replace('>', '');
|
||||
@@ -40,7 +40,7 @@ export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
||||
export async function is_installed(program: string, arg: string): Promise<{ installed: boolean, output: string | null }> {
|
||||
export async function isInstalled(program: string, arg: string): Promise<{ installed: boolean, output: string | null }> {
|
||||
try{
|
||||
const output = await new Command('is-' + program + '-installed', [arg]).execute();
|
||||
if (output.code === 0) {
|
||||
@@ -54,13 +54,42 @@ export async function is_installed(program: string, arg: string): Promise<{ inst
|
||||
}
|
||||
}
|
||||
|
||||
export function extract_version(output: string): string | null {
|
||||
export async function detectDistro(): Promise<string | null> {
|
||||
try{
|
||||
const output = await new Command('detect-distro', ['^ID=', '/etc/os-release']).execute();
|
||||
if (output.code === 0) {
|
||||
return output.stdout;
|
||||
} else {
|
||||
return output.stdout;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function detectDistroBase(distro: string | null): string | null{
|
||||
if(distro) {
|
||||
if(['debian', 'ubuntu', 'pop', 'kali'].includes(distro)) {
|
||||
return 'debian';
|
||||
} else if (['rhel', 'fedora', 'centos', 'rocky'].includes(distro)) {
|
||||
return 'rhel';
|
||||
} else {
|
||||
return 'other';
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function extractVersion(output: string): string | null {
|
||||
const versionPatterns = [
|
||||
/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
|
||||
/apt (\d+\.\d+\.\d+)/, // Pattern for apt
|
||||
/(\d+\.\d+\.\d+)/, // Pattern for dnf
|
||||
/pip (\d+\.\d+)/, // Pattern for pip
|
||||
|
||||
];
|
||||
@@ -73,6 +102,12 @@ export function extract_version(output: string): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function extractDistroId(input: string): string | null {
|
||||
const regex = /ID=([a-zA-Z]+)/;
|
||||
const match = input.match(regex);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
export async function sendStreamInfo(url: string) {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
@@ -81,7 +116,7 @@ export async function sendStreamInfo(url: string) {
|
||||
console.log(output.stdout);
|
||||
const sendStreamData = async () => {
|
||||
try {
|
||||
const streamsstr = JSON.stringify(convert_xml_to_json(extract_xml(output.stdout)))
|
||||
const streamsstr = JSON.stringify(convertXmlToJson(extractXml(output.stdout)))
|
||||
await invoke('receive_frontend_response', { response: streamsstr });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@@ -3,6 +3,10 @@ export interface InstalledPrograms {
|
||||
installed: boolean;
|
||||
version: string | null;
|
||||
};
|
||||
dnf: {
|
||||
installed: boolean;
|
||||
version: string | null;
|
||||
}
|
||||
python: {
|
||||
installed: boolean;
|
||||
version: string | null;
|
||||
|
||||
Reference in New Issue
Block a user