1
1
mirror of https://github.com/neosubhamoy/neodlp.git synced 2026-03-22 19:25:49 +05:30

18 Commits

8 changed files with 192 additions and 17 deletions

View File

@@ -83,9 +83,10 @@ After installing the extension you can do the following directly from the browse
| Platform (OS) | Distribution Channel | Installation Command / Instruction |
| :---- | :---- | :---- |
| Windows x86_64 / ARM64 | WinGet | `winget install neosubhamoy.neodlp` |
| MacOS x86_64 / ARM64 | Homebrew | `brew install neosubhamoy/tap/neodlp` |
| MacOS x86_64 / ARM64 | Curl-Bash Installer | `curl -sSL https://neodlp.neosubhamoy.com/macos_installer.sh \| bash` |
| Linux x86_64 / ARM64 | Curl-Bash Installer | `curl -sSL https://neodlp.neosubhamoy.com/linux_installer.sh \| bash` |
| Arch Linux x86_64 / ARM64 | AUR | `yay -S neodlp` |
| Arch Linux x86_64 / ARM64 | AUR | `yay -S neodlp` or `paru -S neodlp` |
## 🧪 Package Testing Status

View File

@@ -0,0 +1,10 @@
[Desktop Entry]
Type=Application
Name=NeoDLP
Comment=Modern video/audio downloader based on yt-dlp with browser integration.
Icon=com.neosubhamoy.neodlp
Exec=neodlp
Terminal=false
Categories=Utility;
Keywords=neodlp;downloader;yt-dlp-gui;

View File

@@ -0,0 +1,31 @@
<?xml version='1.0' encoding='UTF-8'?>
<component type="desktop-application">
<id>com.neosubhamoy.neodlp</id>
<name>NeoDLP</name>
<summary>Modern video/audio downloader based on yt-dlp with browser integration</summary>
<developer_name>Subhamoy Biswas</developer_name>
<metadata_license>CC0-1.0</metadata_license>
<project_license>MIT</project_license>
<url type="homepage">https://neodlp.neosubhamoy.com</url>
<url type="bugtracker">https://github.com/neosubhamoy/neodlp/issues</url>
<description>
<p>
NeoDLP is a cross-platform desktop application designed for downloading videos and audio from various online sources based on yt-dlp.
It offers modern user interface, lots of customization options and seamless browser integration.
</p>
</description>
<launchable type="desktop-id">com.neosubhamoy.neodlp.desktop</launchable>
<screenshots>
<screenshot type="default">
<image>https://raw.githubusercontent.com/neosubhamoy/neodlp/main/.github/images/downloader.png</image>
<caption>NeoDLP Downloader</caption>
</screenshot>
</screenshots>
<content_rating type="oars-1.1" />
<releases>
<release version="0.4.2" date="2026-02-23">
<url type="details">https://github.com/neosubhamoy/neodlp/releases/tag/v0.4.2</url>
</release>
</releases>
</component>

View File

@@ -64,6 +64,11 @@
"name": "powershell",
"cmd": "powershell",
"args": true
},
{
"name": "sh",
"cmd": "sh",
"args": true
}
]
},

View File

@@ -184,6 +184,16 @@ fn get_current_app_path() -> Result<String, String> {
.into_owned())
}
#[tauri::command]
fn is_flatpak() -> bool {
std::env::var("FLATPAK").is_ok()
}
#[tauri::command]
fn get_appimage_path() -> Option<String> {
std::env::var("APPDIR").ok()
}
#[tauri::command]
async fn update_config(
new_config: Config,
@@ -604,6 +614,8 @@ pub async fn run() {
get_config_file_path,
restart_websocket_server,
get_current_app_path,
is_flatpak,
get_appimage_path
])
.run(tauri::generate_context!())
.expect("error while running tauri application");

View File

@@ -0,0 +1,51 @@
{
"identifier": "com.neosubhamoy.neodlp",
"build": {
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build",
"devUrl": "http://localhost:1420",
"frontendDist": "../dist"
},
"app": {
"windows": [
{
"title": "NeoDLP",
"width": 1080,
"height": 680,
"decorations": false,
"visible": false
}
],
"security": {
"csp": null,
"capabilities": [
"default",
"shell-scope"
]
}
},
"bundle": {
"active": true,
"targets": ["deb"],
"createUpdaterArtifacts": true,
"licenseFile": "../LICENSE",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"externalBin": [
"binaries/yt-dlp",
"binaries/ffmpeg",
"binaries/ffprobe",
"binaries/aria2c",
"binaries/deno",
"binaries/neodlp-pot"
],
"resources": {
"resources/plugins/yt-dlp-plugins/": "yt-dlp-plugins/"
}
}
}

View File

@@ -2,48 +2,112 @@ import { join, resourceDir, homeDir } from "@tauri-apps/api/path";
import * as fs from "@tauri-apps/plugin-fs";
import { useKvPairs } from "@/helpers/use-kvpairs";
import { useSettingsPageStatesStore } from "@/services/store";
import { invoke } from "@tauri-apps/api/core";
import { useLogger } from "@/helpers/use-logger";
import { Command } from "@tauri-apps/plugin-shell";
interface FileMap {
source: string;
destination: string;
dir: string;
content?: string;
}
export function useLinuxRegisterer() {
const { saveKvPair } = useKvPairs();
const appVersion = useSettingsPageStatesStore(state => state.appVersion);
const LOG = useLogger();
const registerToLinux = async () => {
try {
const isFlatpak = await invoke<boolean>('is_flatpak');
const resourceDirPath = isFlatpak ? '/app/lib/neodlp' : await resourceDir();
const homeDirPath = await homeDir();
const flatpakChromeManifestContent = {
name: "com.neosubhamoy.neodlp",
description: "NeoDLP MsgHost",
path: `${homeDirPath}/.local/bin/neodlp-msghost`,
type: "stdio",
allowed_origins: ["chrome-extension://mehopeailfjmiloiiohgicphlcgpompf/"]
};
const flatpakFirefoxManifestContent = {
name: "com.neosubhamoy.neodlp",
description: "NeoDLP MsgHost",
path: `${homeDirPath}/.local/bin/neodlp-msghost`,
type: "stdio",
allowed_extensions: ["neodlp@neosubhamoy.com"]
};
const filesToCopy: FileMap[] = [
{ source: 'yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/getpot_bgutil.py', destination: 'yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/getpot_bgutil.py', dir: 'yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/' },
{ source: 'yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/getpot_bgutil_cli.py', destination: 'yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/getpot_bgutil_cli.py', dir: 'yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/' },
{ source: 'yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/getpot_bgutil_http.py', destination: 'yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/getpot_bgutil_http.py', dir: 'yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/' },
];
const resourceDirPath = await resourceDir();
const homeDirPath = await homeDir();
const filesToCopyFlatpak: FileMap[] = [
{ source: 'chrome.json', destination: '.config/google-chrome/NativeMessagingHosts/com.neosubhamoy.neodlp.json', dir: '.config/google-chrome/NativeMessagingHosts/', content: JSON.stringify(flatpakChromeManifestContent) },
{ source: 'chrome.json', destination: '.config/chromium/NativeMessagingHosts/com.neosubhamoy.neodlp.json', dir: '.config/chromium/NativeMessagingHosts/', content: JSON.stringify(flatpakChromeManifestContent) },
{ source: 'firefox.json', destination: '.mozilla/native-messaging-hosts/com.neosubhamoy.neodlp.json', dir: '.mozilla/native-messaging-hosts/', content: JSON.stringify(flatpakFirefoxManifestContent) },
];
for (const file of filesToCopy) {
const sourcePath = await join(resourceDirPath, file.source);
const destinationDir = await join(homeDirPath, file.dir);
const destinationPath = await join(homeDirPath, file.destination);
LOG.info("LINUX REGISTERER", `Is Flatpak: ${isFlatpak}, Resource dir: ${resourceDirPath}, Home dir: ${homeDirPath}`);
const dirExists = await fs.exists(destinationDir);
if (dirExists) {
await fs.copyFile(sourcePath, destinationPath);
console.log(`File ${file.source} copied successfully to ${destinationPath}`);
} else {
await fs.mkdir(destinationDir, { recursive: true })
console.log(`Created dir ${destinationDir}`);
await fs.copyFile(sourcePath, destinationPath);
console.log(`File ${file.source} copied successfully to ${destinationPath}`);
if (isFlatpak) {
for (const file of filesToCopyFlatpak) {
const sourcePath = await join(resourceDirPath, file.source);
const destinationPath = await join(homeDirPath, file.destination);
const escapedContent = file.content?.replace(/'/g, `'\\''`) || '';
const copyCommand = Command.create('sh', ['-c', 'cp', sourcePath, destinationPath]);
const writeCommand = Command.create('sh', ['-c', `printf '%s' '${escapedContent}' > "${destinationPath}"`]);
if (file.content) {
const writeOutput = await writeCommand.execute();
if (writeOutput.code === 0) {
console.log(`File ${file.destination} created successfully at ${destinationPath}`);
LOG.info("LINUX REGISTERER", `File ${file.destination} created successfully at ${destinationPath}`);
} else {
console.error(`Failed to create file ${file.destination} at ${destinationPath}:`, writeOutput.stderr);
LOG.error("LINUX REGISTERER", `Failed to create file ${file.destination} at ${destinationPath}: ${writeOutput.stderr}`);
return { success: false, message: 'Failed to register' };
}
} else {
const copyOutput = await copyCommand.execute();
if (copyOutput.code === 0) {
console.log(`File ${file.source} copied successfully to ${destinationPath}`);
LOG.info("LINUX REGISTERER", `File ${file.source} copied successfully to ${destinationPath}`);
} else {
console.error(`Failed to copy file ${file.source} to ${destinationPath}:`, copyOutput.stderr);
LOG.error("LINUX REGISTERER", `Failed to copy file ${file.source} to ${destinationPath}: ${copyOutput.stderr}`);
return { success: false, message: 'Failed to register' };
}
}
}
} else {
for (const file of filesToCopy) {
const sourcePath = await join(resourceDirPath, file.source);
const destinationDir = await join(homeDirPath, file.dir);
const destinationPath = await join(homeDirPath, file.destination);
const dirExists = await fs.exists(destinationDir);
if (dirExists) {
await fs.copyFile(sourcePath, destinationPath);
console.log(`File ${file.source} copied successfully to ${destinationPath}`);
LOG.info("LINUX REGISTERER", `File ${file.source} copied successfully to ${destinationPath}`);
} else {
await fs.mkdir(destinationDir, { recursive: true })
console.log(`Created dir ${destinationDir}`);
LOG.info("LINUX REGISTERER", `Created dir ${destinationDir}`);
await fs.copyFile(sourcePath, destinationPath);
console.log(`File ${file.source} copied successfully to ${destinationPath}`);
LOG.info("LINUX REGISTERER", `File ${file.source} copied successfully to ${destinationPath}`);
}
}
}
saveKvPair('linux_registered_version', appVersion);
return { success: true, message: 'Registered successfully' }
} catch (error) {
console.error('Error copying files:', error);
LOG.error("LINUX REGISTERER", `Error copying files: ${error}`);
return { success: false, message: 'Failed to register' }
}
}

View File

@@ -17,10 +17,11 @@ export function useYtDlpUpdater() {
const updateYtDlp = async () => {
const CURRENT_TIMESTAMP = Date.now();
const isFlatpak = await invoke<boolean>('is_flatpak');
setIsUpdatingYtDlp(true);
LOG.info('NEODLP', 'Updating yt-dlp to latest version');
try {
const command = currentPlatform === 'linux' ? Command.create('pkexec', ['yt-dlp', '--update-to', ytDlpUpdateChannel]) : Command.sidecar('binaries/yt-dlp', ['--update-to', ytDlpUpdateChannel]);
const command = currentPlatform === 'linux' && !isFlatpak ? Command.create('pkexec', ['yt-dlp', '--update-to', ytDlpUpdateChannel]) : Command.sidecar('binaries/yt-dlp', ['--update-to', ytDlpUpdateChannel]);
const output = await command.execute();
if (output.code === 0) {
console.log("yt-dlp updated successfully:", output.stdout);