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

9 Commits

10 changed files with 91 additions and 44 deletions

View File

@@ -2,7 +2,7 @@
Type=Application Type=Application
Name=NeoDLP Name=NeoDLP
Comment=Modern video/audio downloader based on yt-dlp with browser integration. Comment=Modern feature-rich video/audio downloader based on yt-dlp.
Icon=com.neosubhamoy.neodlp Icon=com.neosubhamoy.neodlp
Exec=neodlp Exec=neodlp
Terminal=false Terminal=false

View File

@@ -2,7 +2,7 @@
<component type="desktop-application"> <component type="desktop-application">
<id>com.neosubhamoy.neodlp</id> <id>com.neosubhamoy.neodlp</id>
<name>NeoDLP</name> <name>NeoDLP</name>
<summary>Modern video/audio downloader based on yt-dlp with browser integration</summary> <summary>Modern feature-rich video/audio downloader based on yt-dlp</summary>
<developer id="com.neosubhamoy"> <developer id="com.neosubhamoy">
<name>Subhamoy Biswas</name> <name>Subhamoy Biswas</name>
</developer> </developer>
@@ -15,7 +15,7 @@
<p> <p>
NeoDLP is a cross-platform desktop application designed for downloading videos and audio from various online sources based on yt-dlp. 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. It offers modern user interface, lots of features and customization options.
</p> </p>
</description> </description>
<launchable type="desktop-id">com.neosubhamoy.neodlp.desktop</launchable> <launchable type="desktop-id">com.neosubhamoy.neodlp.desktop</launchable>
@@ -39,8 +39,8 @@
</screenshots> </screenshots>
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1" />
<releases> <releases>
<release version="0.4.2" date="2026-03-03"> <release version="0.4.3" date="2026-03-05">
<url type="details">https://github.com/neosubhamoy/neodlp/releases/tag/v0.4.2</url> <url type="details">https://github.com/neosubhamoy/neodlp/releases/tag/v0.4.3</url>
</release> </release>
</releases> </releases>
</component> </component>

View File

@@ -40,6 +40,11 @@
"args": true, "args": true,
"sidecar": true "sidecar": true
}, },
{
"name": "yt-dlp",
"cmd": "yt-dlp",
"args": true
},
{ {
"name": "ffmpeg", "name": "ffmpeg",
"cmd": "ffmpeg", "cmd": "ffmpeg",
@@ -66,9 +71,9 @@
"args": true "args": true
}, },
{ {
"name": "sh", "name": "sh",
"cmd": "sh", "cmd": "sh",
"args": true "args": true
} }
] ]
}, },
@@ -105,6 +110,11 @@
"args": true, "args": true,
"sidecar": true "sidecar": true
}, },
{
"name": "yt-dlp",
"cmd": "yt-dlp",
"args": true
},
{ {
"name": "ffmpeg", "name": "ffmpeg",
"cmd": "ffmpeg", "cmd": "ffmpeg",
@@ -119,6 +129,21 @@
"name": "deno", "name": "deno",
"cmd": "deno", "cmd": "deno",
"args": true "args": true
},
{
"name": "pkexec",
"cmd": "pkexec",
"args": true
},
{
"name": "powershell",
"cmd": "powershell",
"args": true
},
{
"name": "sh",
"cmd": "sh",
"args": true
} }
] ]
} }

View File

@@ -1,8 +1,8 @@
{ {
"identifier": "com.neosubhamoy.neodlp", "identifier": "com.neosubhamoy.neodlp",
"build": { "build": {
"beforeDevCommand": "cargo build --manifest-path=./src-tauri/msghost/Cargo.toml && npm run dev", "beforeDevCommand": "npm run dev",
"beforeBuildCommand": "cargo build --release --manifest-path=./src-tauri/msghost/Cargo.toml && npm run build", "beforeBuildCommand": "npm run build",
"devUrl": "http://localhost:1420", "devUrl": "http://localhost:1420",
"frontendDist": "../dist" "frontendDist": "../dist"
}, },
@@ -37,12 +37,7 @@
"icons/icon.ico" "icons/icon.ico"
], ],
"externalBin": [ "externalBin": [
"binaries/yt-dlp", "binaries/deno"
"binaries/ffmpeg",
"binaries/ffprobe",
"binaries/aria2c",
"binaries/deno",
"binaries/neodlp-pot"
], ],
"resources": { "resources": {
"resources/plugins/yt-dlp-plugins/": "yt-dlp-plugins/" "resources/plugins/yt-dlp-plugins/": "yt-dlp-plugins/"

View File

@@ -257,7 +257,10 @@ export default function App({ children }: { children: React.ReactNode }) {
const fetchYtDlpVersion = async () => { const fetchYtDlpVersion = async () => {
setIsFetchingYtDlpVersion(true); setIsFetchingYtDlpVersion(true);
try { try {
const command = Command.sidecar('binaries/yt-dlp', ['--version']); const isFlatpak = await invoke<boolean>('is_flatpak');
const command = isFlatpak
? Command.create('sh', ['-c', `yt-dlp --version`])
: Command.sidecar('binaries/yt-dlp', ['--version']);
const output = await command.execute(); const output = await command.execute();
if (output.code === 0) { if (output.code === 0) {
const version = output.stdout.trim(); const version = output.stdout.trim();

View File

@@ -1403,6 +1403,8 @@ function AppPoTokenSettings() {
function AppNotificationSettings() { function AppNotificationSettings() {
const { saveSettingsKey } = useSettings(); const { saveSettingsKey } = useSettings();
const isFlatpak = useEnvironmentStore(state => state.isFlatpak);
const enableNotifications = useSettingsPageStatesStore(state => state.settings.enable_notifications); const enableNotifications = useSettingsPageStatesStore(state => state.settings.enable_notifications);
const updateNotification = useSettingsPageStatesStore(state => state.settings.update_notification); const updateNotification = useSettingsPageStatesStore(state => state.settings.update_notification);
const downloadCompletionNotification = useSettingsPageStatesStore(state => state.settings.download_completion_notification); const downloadCompletionNotification = useSettingsPageStatesStore(state => state.settings.download_completion_notification);
@@ -1416,6 +1418,7 @@ function AppNotificationSettings() {
<Switch <Switch
id="enable-notifications" id="enable-notifications"
checked={enableNotifications} checked={enableNotifications}
disabled={isFlatpak}
onCheckedChange={async (checked) => { onCheckedChange={async (checked) => {
if (checked) { if (checked) {
const granted = await isPermissionGranted(); const granted = await isPermissionGranted();
@@ -1441,7 +1444,7 @@ function AppNotificationSettings() {
id="update-notification" id="update-notification"
checked={updateNotification} checked={updateNotification}
onCheckedChange={(checked) => saveSettingsKey('update_notification', checked)} onCheckedChange={(checked) => saveSettingsKey('update_notification', checked)}
disabled={!enableNotifications} disabled={!enableNotifications || isFlatpak}
/> />
<Label htmlFor="update-notification">App Updates</Label> <Label htmlFor="update-notification">App Updates</Label>
</div> </div>
@@ -1450,7 +1453,7 @@ function AppNotificationSettings() {
id="download-completion-notification" id="download-completion-notification"
checked={downloadCompletionNotification} checked={downloadCompletionNotification}
onCheckedChange={(checked) => saveSettingsKey('download_completion_notification', checked)} onCheckedChange={(checked) => saveSettingsKey('download_completion_notification', checked)}
disabled={!enableNotifications} disabled={!enableNotifications || isFlatpak}
/> />
<Label htmlFor="download-completion-notification">Download Completion</Label> <Label htmlFor="download-completion-notification">Download Completion</Label>
</div> </div>
@@ -1813,7 +1816,7 @@ function AppInfoSettings() {
<TriangleAlert className="size-4 stroke-primary" /> <TriangleAlert className="size-4 stroke-primary" />
<AlertTitle className="text-sm">Flatpak Sandbox Detected!</AlertTitle> <AlertTitle className="text-sm">Flatpak Sandbox Detected!</AlertTitle>
<AlertDescription className="text-xs"> <AlertDescription className="text-xs">
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. It looks like you are running NeoDLP in a Flatpak sandbox. Some features like browser integration, desktop notifications, changing download folder, revealing completed downloads in explorer, automatic yt-dlp updates and auto-launch on startup are not available in Flatpak due to sandbox restrictions. To use these features, please install the native linux build (DEB, RPM or AUR) of NeoDLP.
</AlertDescription> </AlertDescription>
</Alert> </Alert>
) : isAppimage ? ( ) : isAppimage ? (
@@ -1821,7 +1824,7 @@ function AppInfoSettings() {
<TriangleAlert className="size-4 stroke-primary" /> <TriangleAlert className="size-4 stroke-primary" />
<AlertTitle className="text-sm">Appimage Environment Detected!</AlertTitle> <AlertTitle className="text-sm">Appimage Environment Detected!</AlertTitle>
<AlertDescription className="text-xs"> <AlertDescription className="text-xs">
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. 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 linux build (DEB, RPM or AUR) of NeoDLP.
</AlertDescription> </AlertDescription>
</Alert> </Alert>
) : ( ) : (

View File

@@ -196,7 +196,10 @@ export default function useDownloader() {
} }
} }
const command = Command.sidecar('binaries/yt-dlp', args); const isFlatpak = await invoke<boolean>('is_flatpak');
const command = isFlatpak
? Command.create('sh', ['-c', `yt-dlp ${args.map(arg => `'${arg.replace(/'/g, "'\\''")}'`).join(' ')}`])
: Command.sidecar('binaries/yt-dlp', args);
let jsonOutput = ''; let jsonOutput = '';
@@ -557,7 +560,10 @@ export default function useDownloader() {
} }
console.log('Starting download with args:', args); console.log('Starting download with args:', args);
const command = Command.sidecar('binaries/yt-dlp', args); const isFlatpak = await invoke<boolean>('is_flatpak');
const command = isFlatpak
? Command.create('sh', ['-c', `yt-dlp ${args.map(arg => `'${arg.replace(/'/g, "'\\''")}'`).join(' ')}`])
: Command.sidecar('binaries/yt-dlp', args);
command.on('close', async (data) => { command.on('close', async (data) => {
if (data.code !== 0) { if (data.code !== 0) {

View File

@@ -21,20 +21,20 @@ export function useLinuxRegisterer() {
const isFlatpak = await invoke<boolean>('is_flatpak'); const isFlatpak = await invoke<boolean>('is_flatpak');
const resourceDirPath = isFlatpak ? '/app/lib/neodlp' : await resourceDir(); const resourceDirPath = isFlatpak ? '/app/lib/neodlp' : await resourceDir();
const homeDirPath = await homeDir(); const homeDirPath = await homeDir();
const flatpakChromeManifestContent = { // const flatpakChromeManifestContent = {
name: "com.neosubhamoy.neodlp", // name: "com.neosubhamoy.neodlp",
description: "NeoDLP MsgHost", // description: "NeoDLP MsgHost",
path: `${homeDirPath}/.local/bin/neodlp-msghost`, // path: `${homeDirPath}/.local/bin/neodlp-msghost`,
type: "stdio", // type: "stdio",
allowed_origins: ["chrome-extension://mehopeailfjmiloiiohgicphlcgpompf/"] // allowed_origins: ["chrome-extension://mehopeailfjmiloiiohgicphlcgpompf/"]
}; // };
const flatpakFirefoxManifestContent = { // const flatpakFirefoxManifestContent = {
name: "com.neosubhamoy.neodlp", // name: "com.neosubhamoy.neodlp",
description: "NeoDLP MsgHost", // description: "NeoDLP MsgHost",
path: `${homeDirPath}/.local/bin/neodlp-msghost`, // path: `${homeDirPath}/.local/bin/neodlp-msghost`,
type: "stdio", // type: "stdio",
allowed_extensions: ["neodlp@neosubhamoy.com"] // allowed_extensions: ["neodlp@neosubhamoy.com"]
}; // };
const filesToCopy: FileMap[] = [ 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.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/' },
@@ -43,18 +43,22 @@ export function useLinuxRegisterer() {
]; ];
const filesToCopyFlatpak: FileMap[] = [ 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/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: '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) }, // { source: 'firefox.json', destination: '.mozilla/native-messaging-hosts/com.neosubhamoy.neodlp.json', dir: '.mozilla/native-messaging-hosts/', content: JSON.stringify(flatpakFirefoxManifestContent) },
{ source: 'neodlp-msghost', destination: '.local/bin/neodlp-msghost', dir: '.local/bin/' }, // { source: 'neodlp-msghost', destination: '.local/bin/neodlp-msghost', dir: '.local/bin/' },
{ source: 'yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/getpot_bgutil.py', destination: '.var/app/com.neosubhamoy.neodlp/config/yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/getpot_bgutil.py', dir: '.var/app/com.neosubhamoy.neodlp/config/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: '.var/app/com.neosubhamoy.neodlp/config/yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/getpot_bgutil_cli.py', dir: '.var/app/com.neosubhamoy.neodlp/config/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: '.var/app/com.neosubhamoy.neodlp/config/yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/getpot_bgutil_http.py', dir: '.var/app/com.neosubhamoy.neodlp/config/yt-dlp-plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins/extractor/' },
]; ];
if (isFlatpak) { if (isFlatpak) {
for (const file of filesToCopyFlatpak) { for (const file of filesToCopyFlatpak) {
const sourcePath = await join(resourceDirPath, file.source); const sourcePath = await join(resourceDirPath, file.source);
const destinationDir = await join(homeDirPath, file.dir);
const destinationPath = await join(homeDirPath, file.destination); const destinationPath = await join(homeDirPath, file.destination);
const escapedContent = file.content?.replace(/'/g, `'\\''`) || ''; const escapedContent = file.content?.replace(/'/g, `'\\''`) || '';
const copyCommand = Command.create('sh', ['-c', `cp "${sourcePath}" "${destinationPath}"`]); const copyCommand = Command.create('sh', ['-c', `mkdir -p "${destinationDir}" && cp "${sourcePath}" "${destinationPath}"`]);
const writeCommand = Command.create('sh', ['-c', `printf '%s' '${escapedContent}' > "${destinationPath}"`]); const writeCommand = Command.create('sh', ['-c', `printf '%s' '${escapedContent}' > "${destinationPath}"`]);
if (file.content) { if (file.content) {

View File

@@ -17,7 +17,12 @@ export default function usePotServer() {
}; };
const startPotServer = async (port?: number) => { const startPotServer = async (port?: number) => {
const runCommand = Command.sidecar('binaries/neodlp-pot', [ const isFlatpak = await invoke<boolean>('is_flatpak');
const runCommand = isFlatpak
? Command.create('sh', [
'-c', `/app/bin/neodlp-pot server --port ${port ? port.toString() : potServerPort.toString()}`
])
: Command.sidecar('binaries/neodlp-pot', [
'server', 'server',
'--port', '--port',
port ? port.toString() : potServerPort.toString(), port ? port.toString() : potServerPort.toString(),

View File

@@ -21,7 +21,13 @@ export function useYtDlpUpdater() {
setIsUpdatingYtDlp(true); setIsUpdatingYtDlp(true);
LOG.info('NEODLP', 'Updating yt-dlp to latest version'); LOG.info('NEODLP', 'Updating yt-dlp to latest version');
try { try {
const command = currentPlatform === 'linux' && !isFlatpak ? Command.create('pkexec', ['yt-dlp', '--update-to', ytDlpUpdateChannel]) : Command.sidecar('binaries/yt-dlp', ['--update-to', ytDlpUpdateChannel]); const command = currentPlatform === 'linux' && isFlatpak
? ytDlpUpdateChannel === 'nightly'
? Command.create('sh', ['-c', 'pip3 install -U --pre "yt-dlp[default,curl-cffi]"'])
: Command.create('sh', ['-c', 'pip3 install -U "yt-dlp[default,curl-cffi]"'])
: currentPlatform === 'linux'
? Command.create('pkexec', ['yt-dlp', '--update-to', ytDlpUpdateChannel])
: Command.sidecar('binaries/yt-dlp', ['--update-to', ytDlpUpdateChannel]);
const output = await command.execute(); const output = await command.execute();
if (output.code === 0) { if (output.code === 0) {
console.log("yt-dlp updated successfully:", output.stdout); console.log("yt-dlp updated successfully:", output.stdout);