1
1
mirror of https://github.com/neosubhamoy/neodlp.git synced 2026-02-05 03:02:23 +05:30

9 Commits

51 changed files with 1393 additions and 479 deletions

2
.gitattributes vendored
View File

@@ -1,3 +1 @@
* text=auto eol=lf
src-tauri/binaries/* filter=lfs diff=lfs merge=lfs -text

View File

@@ -27,18 +27,6 @@ jobs:
- name: 🚚 Checkout repository
uses: actions/checkout@v5
- name: 🔐 Configure Git LFS
shell: bash
run: |
git config --global credential.helper store
echo "https://${{ secrets.LFS_USERNAME }}:${{ secrets.LFS_PASSWORD }}@lfs.neosubhamoy.com" > ~/.git-credentials
- name: 📥 Pull LFS objects
shell: bash
run: |
git lfs install
git lfs pull
- name: 🛠️ Install dependencies
if: matrix.platform == 'ubuntu-22.04' || matrix.platform == 'ubuntu-22.04-arm'
run: |
@@ -64,6 +52,9 @@ jobs:
- name: 🛠️ Install frontend dependencies
run: npm install
- name: 📥 Download binaries
run: npm run download
- name: 📄 Read and Process CHANGELOG (Unix)
if: matrix.platform != 'windows-latest'
id: changelog_unix

18
.gitignore vendored
View File

@@ -1,3 +1,14 @@
node_modules
dist
dist-ssr
*.local
.github/workflows/.secrets
/target/
src-tauri/binaries/*
!src-tauri/binaries/.gitkeep
src-tauri/resources/downloads/*
!src-tauri/resources/downloads/.gitkeep
# Logs
logs
*.log
@@ -7,13 +18,6 @@ yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
.github/workflows/.secrets
/target/
# Editor directories and files
.vscode/*
!.vscode/extensions.json

View File

@@ -1,2 +0,0 @@
[lfs]
url = https://lfs.neosubhamoy.com

View File

@@ -1,14 +1,13 @@
### ✨ Changelog
- Added Debug Mode (with log customization)
- Added quick paste and clear buttons on downloader
- Fixed browser integration not working on Windows MSI install
- Fixed the occasional freezing issue on macOS while downloading large files
- Now Linux (deb, rpm) packages supports in-built app-updater
- Other minor fixes and improvements
- HOTFIX: yt-dlp exiting with code 2 while resolving deno on macOS
- Also, a small correction: Linux (deb, rpm) packages are not yet self-updateable
### 📝 Notes
> [!TIP]
> This is a hotfix release for macOS only, You can skip this update if you are on other platforms
> [!CAUTION]
> This is a breaking update if you are coming from older version than `v0.3.0`. Users are adviced to complete/cancel all paused downloads before updating to this version, otherwise paused downloads may not resume properly or re-start from the begining.
@@ -23,7 +22,7 @@
| yt-dlp (updateable) | ffmpeg | ffprobe | aria2c | deno |
| :---- | :---- | :---- | :---- | :---- |
| v2025.10.25.232842 (nightly) | v7.1.1 | v7.1.1 | v1.37.0 | v2.5.4 |
| v2025.11.05.232946 (nightly) | v7.1.1 | v7.1.1 | v1.37.0 | v2.5.6 |
> ‼️ Linux builds (deb, rpm) does not ships with `ffmpeg` and `ffprobe` (though it will be auto installed as a dependency by your package manager, if you are on fedora make sure to [enable rpmfusion free+nonfree repos](https://docs.fedoraproject.org/en-US/quick-docs/rpmfusion-setup/#_enabling_the_rpm_fusion_repositories_using_command_line_utilities) before installing the rpm package)
@@ -31,12 +30,12 @@
### ⬇️ Download Section
| Arch\OS | Windows (msi) | Windows (exe) | Linux (deb) | Linux (rpm) | Linux (AppImage) | MacOS (dmg) | MacOS (app) |
| Architecture | Windows (msi) ⬆️ | Windows (exe) ⬆️ | Linux (deb) | Linux (rpm) | Linux (AppImage) ⬆️ | MacOS (dmg) ⬆️ | MacOS (app) ⬆️ |
| :---- | :---- | :---- | :---- | :---- | :---- | :---- | :---- |
| x86_64 | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_x64_en-US_windows.msi) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_x64-setup_windows.exe) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_amd64_linux.deb) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP-<version>-1.x86_64_linux.rpm) | 🚫 [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_amd64_linux.AppImage) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_x64_darwin.dmg) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_darwin_x64.app.tar.gz) |
| ARM64 | N/A | 🪟 [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_x64-setup_windows.exe) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_arm64_linux.deb) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP-<version>-1.aarch64_linux.rpm) | N/A | ⚠️ [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_aarch64_darwin.dmg) | ⚠️ [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_darwin_aarch64.app.tar.gz) |
> ⬆️ Now, all packages supports in-built app-updater
> ⬆️ icon indicates this packaging format supports in-built app-updater
> 🪟 Windows x86_64 binary also works on ARM64 (Windows on ARM) devices with emulation (Not planning to release native Windows ARM64 build anytime soon as, x86_64 one works fine on ARM64 without noticeable performance impact)

View File

@@ -67,7 +67,7 @@ After installing the extension you can do the following directly from the browse
1. Download the latest [NeoDLP](https://github.com/neosubhamoy/neodlp/releases/latest) release based on your OS and CPU Architecture, then install it! -OR- Install it directly from an available distribution channel (listed below)
| Arch\OS | Windows | Linux | MacOS |
| Architecture | Windows | Linux | MacOS |
| :---- | :---- | :---- | :---- |
| x86_64 | ✅ [Download](https://github.com/neosubhamoy/neodlp/releases/latest) | ✅ [Download](https://github.com/neosubhamoy/neodlp/releases/latest) | ✅ [Download](https://github.com/neosubhamoy/neodlp/releases/latest) |
| ARM64 | ✅ Emulation | ✅ [Download](https://github.com/neosubhamoy/neodlp/releases/latest) | ✅ [Download](https://github.com/neosubhamoy/neodlp/releases/latest) |
@@ -139,13 +139,14 @@ NeoDLP is and will be always FREE to Use and Open-Sourced for Everyone. On the o
Want to be part of this? Feel free to contribute...!! Pull Requests are always welcome...!! (^_^) Follow these simple steps to start building:
* Make sure to install [Rust](https://www.rust-lang.org/tools/install), [Node.js](https://nodejs.org/en), [Git](https://git-scm.com/downloads) and [Git-LFS](https://git-lfs.com/) before proceeding.
* Make sure to install [Rust](https://www.rust-lang.org/tools/install), [Node.js](https://nodejs.org/en), and [Git](https://git-scm.com/downloads) before proceeding.
* Install [Tauri Prerequisites](https://v2.tauri.app/start/prerequisites/) for your OS / platform
1. Fork this repo in your github account.
2. Git clone the forked repo in your local machine. (**NOTE:** I've recently switched from GitHub LFS Server to my own self-hosted LFS Server! Cause GitHub LFS Storage is too expencive for me and NeoDLP requires a lots of LFS bandwidth. So, If you currently clone the repo it will clone the codebase but not the LFS Objects, If you want to clone the LFS Objects unfortunately you have to ask me for auth credentials - which will be only provided to you in certain conditions)
2. Git clone the forked repo in your local machine.
3. Create a git branch (related to the feature you are working on) (Optional - Recommended)
4. Install Node.js dependencies: `npm install`
5. Run development / build process
5. Download binaries (for current platform): `npm run download`
6. Run development / build process
> [!WARNING]
> Make sure to run the `build` command once before running the `dev` command for the first time to avoid compile time errors
```code
@@ -176,7 +177,7 @@ Noticed any Bug? or Want to give me some suggetion? Always feel free to open a [
## 💫 Credits
- NeoDLP's 'Format Selection' options are inspired from the [Seal](https://github.com/JunkFood02/Seal) app by [@JunkFood02](https://github.com/JunkFood02)
- Aria2 Windows x86_64 and Linux x86_64 static binaries are built by [@asdo92](https://github.com/asdo92/aria2-static-builds)
- Aria2 Linux x86_64 static binaries are built by [@asdo92](https://github.com/asdo92/aria2-static-builds)
## 📝 License

687
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,49 +1,51 @@
{
"name": "neodlp",
"private": true,
"version": "0.3.2",
"version": "0.3.4",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"tauri": "tauri"
"tauri": "tauri",
"download": "node ./scripts/download-bins.js"
},
"dependencies": {
"@hookform/resolvers": "^5.2.2",
"@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-aspect-ratio": "^1.1.7",
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-aspect-ratio": "^1.1.8",
"@radix-ui/react-avatar": "^1.1.11",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-context-menu": "^2.2.16",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-hover-card": "^1.1.15",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-menubar": "^1.1.16",
"@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-progress": "^1.1.8",
"@radix-ui/react-radio-group": "^1.3.8",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-slider": "^1.3.6",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toast": "^1.2.15",
"@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8",
"@tanstack/react-query": "^5.90.5",
"@tanstack/react-query": "^5.90.7",
"@tanstack/react-query-devtools": "^5.90.2",
"@tauri-apps/api": "^2.9.0",
"@tauri-apps/plugin-clipboard-manager": "^2.3.2",
"@tauri-apps/plugin-dialog": "^2.4.2",
"@tauri-apps/plugin-fs": "^2.4.4",
"@tauri-apps/plugin-notification": "^2.3.3",
"@tauri-apps/plugin-opener": "^2.5.2",
"@tauri-apps/plugin-os": "^2.3.2",
"@tauri-apps/plugin-process": "^2.3.1",
@@ -56,14 +58,14 @@
"date-fns": "^4.1.0",
"embla-carousel-react": "^8.6.0",
"input-otp": "^1.4.2",
"lucide-react": "^0.548.0",
"lucide-react": "^0.552.0",
"next-themes": "^0.4.6",
"react": "^19.2.0",
"react-day-picker": "^9.11.1",
"react-dom": "^19.2.0",
"react-hook-form": "^7.65.0",
"react-hook-form": "^7.66.0",
"react-resizable-panels": "^3.0.6",
"react-router-dom": "^7.9.4",
"react-router-dom": "^7.9.5",
"recharts": "^3.3.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
@@ -73,17 +75,17 @@
"zustand": "^5.0.8"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.16",
"@tailwindcss/vite": "^4.1.16",
"@tauri-apps/cli": "^2.9.1",
"@types/node": "^24.9.1",
"@tailwindcss/postcss": "^4.1.17",
"@tailwindcss/vite": "^4.1.17",
"@tauri-apps/cli": "^2.9.3",
"@types/node": "^24.10.0",
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.2",
"@vitejs/plugin-react": "^5.1.0",
"postcss": "^8.5.6",
"tailwindcss": "^4.1.16",
"tailwindcss": "^4.1.17",
"tw-animate-css": "^1.4.0",
"typescript": "~5.9.3",
"vite": "^7.1.12"
"vite": "^7.2.1"
}
}

442
scripts/download-bins.js Normal file
View File

@@ -0,0 +1,442 @@
import os from 'os';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { execSync } from 'child_process';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.resolve(__dirname, '..');
const downloadDir = path.join(projectRoot, 'src-tauri', 'resources', 'downloads');
const binDir = path.join(projectRoot, 'src-tauri', 'binaries');
const platform = os.platform();
const targetPlatform = process.argv[2];
const targetBin = process.argv[3];
const versions = {
'yt-dlp': 'latest',
'ffmpeg-ffprobe': 'latest',
'deno': 'latest',
'aria2c': '1.37.0',
};
const binaries = {
'yt-dlp': [
{
name: 'yt-dlp-x86_64-pc-windows-msvc',
platform: 'win32',
url: `https://github.com/yt-dlp/yt-dlp-nightly-builds/releases${versions['yt-dlp'] === 'latest' ? '/latest' : ''}/download${versions['yt-dlp'] !== 'latest' ? '/'+versions['yt-dlp'] : ''}/yt-dlp.exe`,
src: path.join(downloadDir, 'yt-dlp-x86_64-pc-windows-msvc.exe'),
dest: [
path.join(binDir, 'yt-dlp-x86_64-pc-windows-msvc.exe')
],
archive: null,
cleanup: [
path.join(downloadDir, 'yt-dlp-x86_64-pc-windows-msvc.exe')
]
},
{
name: 'yt-dlp-x86_64-unknown-linux-gnu',
platform: 'linux',
url: `https://github.com/yt-dlp/yt-dlp-nightly-builds/releases${versions['yt-dlp'] === 'latest' ? '/latest' : ''}/download${versions['yt-dlp'] !== 'latest' ? '/'+versions['yt-dlp'] : ''}/yt-dlp_linux`,
src: path.join(downloadDir, 'yt-dlp-x86_64-unknown-linux-gnu'),
dest: [
path.join(binDir, 'yt-dlp-x86_64-unknown-linux-gnu')
],
archive: null,
cleanup: [
path.join(downloadDir, 'yt-dlp-x86_64-unknown-linux-gnu')
]
},
{
name: 'yt-dlp-aarch64-unknown-linux-gnu',
platform: 'linux',
url: `https://github.com/yt-dlp/yt-dlp-nightly-builds/releases${versions['yt-dlp'] === 'latest' ? '/latest' : ''}/download${versions['yt-dlp'] !== 'latest' ? '/'+versions['yt-dlp'] : ''}/yt-dlp_linux_aarch64`,
src: path.join(downloadDir, 'yt-dlp-aarch64-unknown-linux-gnu'),
dest: [
path.join(binDir, 'yt-dlp-aarch64-unknown-linux-gnu')
],
archive: null,
cleanup: [
path.join(downloadDir, 'yt-dlp-aarch64-unknown-linux-gnu')
]
},
{
name: 'yt-dlp-universal-apple-darwin',
platform: 'darwin',
url: `https://github.com/yt-dlp/yt-dlp-nightly-builds/releases${versions['yt-dlp'] === 'latest' ? '/latest' : ''}/download${versions['yt-dlp'] !== 'latest' ? '/'+versions['yt-dlp'] : ''}/yt-dlp_macos`,
src: path.join(downloadDir, 'yt-dlp-universal-apple-darwin'),
dest: [
path.join(binDir, 'yt-dlp-x86_64-apple-darwin'),
path.join(binDir, 'yt-dlp-aarch64-apple-darwin')
],
archive: null,
cleanup: [
path.join(downloadDir, 'yt-dlp-universal-apple-darwin')
]
},
],
'ffmpeg-ffprobe': [
{
name: 'ffmpeg-ffprobe-x86_64-pc-windows-msvc',
platform: 'win32',
url: `https://github.com/yt-dlp/FFmpeg-Builds/releases${versions['ffmpeg-ffprobe'] === 'latest' ? '/latest' : ''}/download${versions['ffmpeg-ffprobe'] !== 'latest' ? '/'+versions['ffmpeg-ffprobe'] : ''}/ffmpeg-master-latest-win64-gpl.zip`,
src: path.join(downloadDir, 'ffmpeg-master-latest-win64-gpl.zip'),
dest: null,
archive: {
type: 'zip',
binSrc: [
path.join(downloadDir, 'ffmpeg-master-latest-win64-gpl', 'bin', 'ffmpeg.exe'),
path.join(downloadDir, 'ffmpeg-master-latest-win64-gpl', 'bin', 'ffprobe.exe')
],
binDest: [
path.join(binDir, 'ffmpeg-x86_64-pc-windows-msvc.exe'),
path.join(binDir, 'ffprobe-x86_64-pc-windows-msvc.exe')
]
},
cleanup: [
path.join(downloadDir, 'ffmpeg-master-latest-win64-gpl.zip'),
path.join(downloadDir, 'ffmpeg-master-latest-win64-gpl')
]
},
{
name: 'ffmpeg-ffprobe-x86_64-unknown-linux-gnu',
platform: 'linux',
url: `https://github.com/yt-dlp/FFmpeg-Builds/releases${versions['ffmpeg-ffprobe'] === 'latest' ? '/latest' : ''}/download${versions['ffmpeg-ffprobe'] !== 'latest' ? '/'+versions['ffmpeg-ffprobe'] : ''}/ffmpeg-master-latest-linux64-gpl.tar.xz`,
src: path.join(downloadDir, 'ffmpeg-master-latest-linux64-gpl.tar.xz'),
dest: null,
archive: {
type: 'tar.xz',
binSrc: [
path.join(downloadDir, 'ffmpeg-master-latest-linux64-gpl', 'bin', 'ffmpeg'),
path.join(downloadDir, 'ffmpeg-master-latest-linux64-gpl', 'bin', 'ffprobe')
],
binDest: [
path.join(binDir, 'ffmpeg-x86_64-unknown-linux-gnu'),
path.join(binDir, 'ffprobe-x86_64-unknown-linux-gnu')
]
},
cleanup: [
path.join(downloadDir, 'ffmpeg-master-latest-linux64-gpl.tar.xz'),
path.join(downloadDir, 'ffmpeg-master-latest-linux64-gpl')
]
},
{
name: 'ffmpeg-ffprobe-aarch64-unknown-linux-gnu',
platform: 'linux',
url: `https://github.com/yt-dlp/FFmpeg-Builds/releases${versions['ffmpeg-ffprobe'] === 'latest' ? '/latest' : ''}/download${versions['ffmpeg-ffprobe'] !== 'latest' ? '/'+versions['ffmpeg-ffprobe'] : ''}/ffmpeg-master-latest-linuxarm64-gpl.tar.xz`,
src: path.join(downloadDir, 'ffmpeg-master-latest-linuxarm64-gpl.tar.xz'),
dest: null,
archive: {
type: 'tar.xz',
binSrc: [
path.join(downloadDir, 'ffmpeg-master-latest-linuxarm64-gpl', 'bin', 'ffmpeg'),
path.join(downloadDir, 'ffmpeg-master-latest-linuxarm64-gpl', 'bin', 'ffprobe')
],
binDest: [
path.join(binDir, 'ffmpeg-aarch64-unknown-linux-gnu'),
path.join(binDir, 'ffprobe-aarch64-unknown-linux-gnu')
]
},
cleanup: [
path.join(downloadDir, 'ffmpeg-master-latest-linuxarm64-gpl.tar.xz'),
path.join(downloadDir, 'ffmpeg-master-latest-linuxarm64-gpl')
]
},
{
name: 'ffmpeg-universal-apple-darwin',
platform: 'darwin',
url: `https://evermeet.cx/ffmpeg/get/zip`,
src: path.join(downloadDir, 'ffmpeg-universal-apple-darwin.zip'),
dest: null,
archive: {
type: 'zip',
binSrc: [
path.join(downloadDir, 'ffmpeg'),
path.join(downloadDir, 'ffmpeg')
],
binDest: [
path.join(binDir, 'ffmpeg-x86_64-apple-darwin'),
path.join(binDir, 'ffmpeg-aarch64-apple-darwin')
]
},
cleanup: [
path.join(downloadDir, 'ffmpeg-universal-apple-darwin.zip'),
path.join(downloadDir, 'ffmpeg')
]
},
{
name: 'ffprobe-universal-apple-darwin',
platform: 'darwin',
url: `https://evermeet.cx/ffmpeg/get/ffprobe/zip`,
src: path.join(downloadDir, 'ffprobe-universal-apple-darwin.zip'),
dest: null,
archive: {
type: 'zip',
binSrc: [
path.join(downloadDir, 'ffprobe'),
path.join(downloadDir, 'ffprobe')
],
binDest: [
path.join(binDir, 'ffprobe-x86_64-apple-darwin'),
path.join(binDir, 'ffprobe-aarch64-apple-darwin')
]
},
cleanup: [
path.join(downloadDir, 'ffprobe-universal-apple-darwin.zip'),
path.join(downloadDir, 'ffprobe')
]
}
],
'deno': [
{
name: 'deno-x86_64-pc-windows-msvc',
platform: 'win32',
url: `https://github.com/denoland/deno/releases${versions['deno'] === 'latest' ? '/latest' : ''}/download${versions['deno'] !== 'latest' ? '/'+versions['deno'] : ''}/deno-x86_64-pc-windows-msvc.zip`,
src: path.join(downloadDir, 'deno-x86_64-pc-windows-msvc.zip'),
dest: null,
archive: {
type: 'zip',
binSrc: [
path.join(downloadDir, 'deno.exe')
],
binDest: [
path.join(binDir, 'deno-x86_64-pc-windows-msvc.exe')
]
},
cleanup: [
path.join(downloadDir, 'deno-x86_64-pc-windows-msvc.zip'),
path.join(downloadDir, 'deno.exe')
]
},
{
name: 'deno-x86_64-unknown-linux-gnu',
platform: 'linux',
url: `https://github.com/denoland/deno/releases${versions['deno'] === 'latest' ? '/latest' : ''}/download${versions['deno'] !== 'latest' ? '/'+versions['deno'] : ''}/deno-x86_64-unknown-linux-gnu.zip`,
src: path.join(downloadDir, 'deno-x86_64-unknown-linux-gnu.zip'),
dest: null,
archive: {
type: 'zip',
binSrc: [
path.join(downloadDir, 'deno')
],
binDest: [
path.join(binDir, 'deno-x86_64-unknown-linux-gnu')
]
},
cleanup: [
path.join(downloadDir, 'deno-x86_64-unknown-linux-gnu.zip'),
path.join(downloadDir, 'deno')
]
},
{
name: 'deno-aarch64-unknown-linux-gnu',
platform: 'linux',
url: `https://github.com/denoland/deno/releases${versions['deno'] === 'latest' ? '/latest' : ''}/download${versions['deno'] !== 'latest' ? '/'+versions['deno'] : ''}/deno-aarch64-unknown-linux-gnu.zip`,
src: path.join(downloadDir, 'deno-aarch64-unknown-linux-gnu.zip'),
dest: null,
archive: {
type: 'zip',
binSrc: [
path.join(downloadDir, 'deno')
],
binDest: [
path.join(binDir, 'deno-aarch64-unknown-linux-gnu')
]
},
cleanup: [
path.join(downloadDir, 'deno-aarch64-unknown-linux-gnu.zip'),
path.join(downloadDir, 'deno')
]
},
{
name: 'deno-x86_64-apple-darwin',
platform: 'darwin',
url: `https://github.com/denoland/deno/releases${versions['deno'] === 'latest' ? '/latest' : ''}/download${versions['deno'] !== 'latest' ? '/'+versions['deno'] : ''}/deno-x86_64-apple-darwin.zip`,
src: path.join(downloadDir, 'deno-x86_64-apple-darwin.zip'),
dest: null,
archive: {
type: 'zip',
binSrc: [
path.join(downloadDir, 'deno')
],
binDest: [
path.join(binDir, 'deno-x86_64-apple-darwin')
]
},
cleanup: [
path.join(downloadDir, 'deno-x86_64-apple-darwin.zip'),
path.join(downloadDir, 'deno')
]
},
{
name: 'deno-aarch64-apple-darwin',
platform: 'darwin',
url: `https://github.com/denoland/deno/releases${versions['deno'] === 'latest' ? '/latest' : ''}/download${versions['deno'] !== 'latest' ? '/'+versions['deno'] : ''}/deno-aarch64-apple-darwin.zip`,
src: path.join(downloadDir, 'deno-aarch64-apple-darwin.zip'),
dest: null,
archive: {
type: 'zip',
binSrc: [
path.join(downloadDir, 'deno')
],
binDest: [
path.join(binDir, 'deno-aarch64-apple-darwin')
]
},
cleanup: [
path.join(downloadDir, 'deno-aarch64-apple-darwin.zip'),
path.join(downloadDir, 'deno')
]
}
],
'aria2c': [
{
name: 'aria2c-x86_64-pc-windows-msvc',
platform: 'win32',
url: `https://github.com/aria2/aria2/releases/download/release-${versions['aria2c']}/aria2-${versions['aria2c']}-win-64bit-build1.zip`,
src: path.join(downloadDir, `aria2-${versions['aria2c']}-win-64bit-build1.zip`),
dest: null,
archive: {
type: 'zip',
binSrc: [
path.join(downloadDir, `aria2-${versions['aria2c']}-win-64bit-build1`, 'aria2c.exe')
],
binDest: [
path.join(binDir, 'aria2c-x86_64-pc-windows-msvc.exe')
]
},
cleanup: [
path.join(downloadDir, `aria2-${versions['aria2c']}-win-64bit-build1.zip`),
path.join(downloadDir, `aria2-${versions['aria2c']}-win-64bit-build1`)
]
},
{
name: 'aria2c-x86_64-unknown-linux-gnu',
platform: 'linux',
url: `https://github.com/asdo92/aria2-static-builds/releases/download/v${versions['aria2c']}/aria2-${versions['aria2c']}-linux-gnu-64bit-build1.tar.bz2`,
src: path.join(downloadDir, `aria2-${versions['aria2c']}-linux-gnu-64bit-build1.tar.bz2`),
dest: null,
archive: {
type: 'tar.bz2',
binSrc: [
path.join(downloadDir, `aria2-${versions['aria2c']}-linux-gnu-64bit-build1`, 'aria2c')
],
binDest: [
path.join(binDir, 'aria2c-x86_64-unknown-linux-gnu')
]
},
cleanup: [
path.join(downloadDir, `aria2-${versions['aria2c']}-linux-gnu-64bit-build1.tar.bz2`),
path.join(downloadDir, `aria2-${versions['aria2c']}-linux-gnu-64bit-build1`)
]
},
{
name: 'aria2c-aarch64-unknown-linux-gnu',
platform: 'linux',
url: `https://github.com/aria2/aria2/releases/download/release-${versions['aria2c']}/aria2-${versions['aria2c']}-aarch64-linux-android-build1.zip`,
src: path.join(downloadDir, `aria2-${versions['aria2c']}-aarch64-linux-android-build1.zip`),
dest: null,
archive: {
type: 'zip',
binSrc: [
path.join(downloadDir, `aria2-${versions['aria2c']}-aarch64-linux-android-build1`, 'aria2c')
],
binDest: [
path.join(binDir, 'aria2c-aarch64-unknown-linux-gnu')
]
},
cleanup: [
path.join(downloadDir, `aria2-${versions['aria2c']}-aarch64-linux-android-build1.zip`),
path.join(downloadDir, `aria2-${versions['aria2c']}-aarch64-linux-android-build1`)
]
}
]
}
function downloadAndProcess(bin) {
console.log(`=> Processing: ${bin.name}`);
console.log(`Downloading: ${bin.url}`);
if (platform === 'win32') {
execSync(`powershell -Command "Invoke-WebRequest -Uri '${bin.url}' -OutFile '${bin.src}'"`, { stdio: 'inherit' });
} else {
execSync(`curl -L "${bin.url}" -o "${bin.src}"`, { stdio: 'inherit' });
}
if (bin.archive) {
console.log(`Extracting: ${bin.src}`);
if (platform === 'win32' && bin.archive.type === 'zip') {
execSync(`powershell -Command "Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::ExtractToDirectory('${bin.src}', '${downloadDir}')"`, { stdio: 'inherit' });
} else if (bin.archive.type === 'tar.bz2') {
execSync(`tar -xjf "${bin.src}" -C "${downloadDir}"`, { stdio: 'inherit' });
} else if (bin.archive.type === 'zip') {
execSync(`unzip -o "${bin.src}" -d "${downloadDir}"`, { stdio: 'inherit' });
} else {
execSync(`tar -xf "${bin.src}" -C "${downloadDir}"`, { stdio: 'inherit' });
}
bin.archive.binSrc.forEach((src, index) => {
const dest = bin.archive.binDest[index];
console.log(`Moving: "${src}" to "${dest}"`);
fs.copyFileSync(src, dest);
if (platform !== 'win32') {
fs.chmodSync(dest, 0o755);
}
});
} else if (bin.dest) {
bin.dest.forEach((dest) => {
console.log(`Moving: "${bin.src}" to "${dest}"`);
fs.copyFileSync(bin.src, dest);
if (platform !== 'win32') {
fs.chmodSync(dest, 0o755);
}
});
}
bin.cleanup.forEach((item) => {
if (fs.existsSync(item)) {
console.log(`Cleaning: "${item}"`);
const stats = fs.statSync(item);
if (stats.isDirectory()) {
fs.rmSync(item, { recursive: true, force: true });
} else {
fs.unlinkSync(item);
}
}
});
}
if (targetPlatform && !['win32', 'linux', 'darwin', 'all'].includes(targetPlatform)) {
console.error(`ERROR: Invalid platform specified: '${targetPlatform}'. Use one of: win32, linux, darwin, or all`);
process.exit(1);
}
if (targetBin && !binaries.hasOwnProperty(targetBin) && targetBin !== 'all') {
console.error(`ERROR: Invalid binary specified: '${targetBin}'. Use one of: ${Object.keys(binaries).join(', ')}, or all`);
process.exit(1);
}
const effectivePlatform = targetPlatform || platform;
const effectiveBin = targetBin || 'all';
console.log(`RUNNING: 📦 Binary Downloader (platform: ${effectivePlatform} | binary: ${effectiveBin})`);
Object.keys(binaries).forEach((binKey) => {
if (effectiveBin !== 'all' && binKey !== effectiveBin) {
return;
}
binaries[binKey].forEach((bin) => {
if (effectivePlatform !== 'all' && bin.platform !== effectivePlatform) {
return;
}
downloadAndProcess(bin);
});
});
console.log('✅ Downloads Completed');

239
src-tauri/Cargo.lock generated
View File

@@ -10,9 +10,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aho-corasick"
version = "1.1.3"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
@@ -475,9 +475,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.43"
version = "1.2.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2"
checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -1977,9 +1977,9 @@ dependencies = [
[[package]]
name = "icu_collections"
version = "2.0.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
dependencies = [
"displaydoc",
"potential_utf",
@@ -1990,9 +1990,9 @@ dependencies = [
[[package]]
name = "icu_locale_core"
version = "2.0.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
dependencies = [
"displaydoc",
"litemap",
@@ -2003,11 +2003,10 @@ dependencies = [
[[package]]
name = "icu_normalizer"
version = "2.0.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
dependencies = [
"displaydoc",
"icu_collections",
"icu_normalizer_data",
"icu_properties",
@@ -2018,42 +2017,38 @@ dependencies = [
[[package]]
name = "icu_normalizer_data"
version = "2.0.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
[[package]]
name = "icu_properties"
version = "2.0.1"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99"
dependencies = [
"displaydoc",
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
"potential_utf",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "2.0.1"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899"
[[package]]
name = "icu_provider"
version = "2.0.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
dependencies = [
"displaydoc",
"icu_locale_core",
"stable_deref_trait",
"tinystr",
"writeable",
"yoke",
"zerofrom",
@@ -2142,9 +2137,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
[[package]]
name = "iri-string"
version = "0.7.8"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397"
dependencies = [
"memchr",
"serde",
@@ -2222,9 +2217,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "js-sys"
version = "0.3.81"
version = "0.3.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305"
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -2376,9 +2371,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "litemap"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
[[package]]
name = "lock_api"
@@ -2407,6 +2402,18 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "mac-notification-sys"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee70bb2bba058d58e252d2944582d634fc884fc9c489a966d428dedcf653e97"
dependencies = [
"cc",
"objc2 0.6.3",
"objc2-foundation 0.3.2",
"time",
]
[[package]]
name = "markup5ever"
version = "0.14.1"
@@ -2504,9 +2511,9 @@ dependencies = [
[[package]]
name = "moxcms"
version = "0.7.8"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692af879e4d9383c0fd9dec15524af6b6977c8bf1c6b278a4526d5341347c574"
checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6"
dependencies = [
"num-traits",
"pxfm",
@@ -2582,7 +2589,7 @@ dependencies = [
[[package]]
name = "neodlp"
version = "0.3.2"
version = "0.3.4"
dependencies = [
"base64 0.22.1",
"directories",
@@ -2597,6 +2604,7 @@ dependencies = [
"tauri-plugin-clipboard-manager",
"tauri-plugin-dialog",
"tauri-plugin-fs",
"tauri-plugin-notification",
"tauri-plugin-opener",
"tauri-plugin-os",
"tauri-plugin-process",
@@ -2656,12 +2664,25 @@ dependencies = [
]
[[package]]
name = "num-bigint-dig"
version = "0.8.4"
name = "notify-rust"
version = "4.11.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
checksum = "6442248665a5aa2514e794af3b39661a8e73033b1cc5e59899e1276117ee4400"
dependencies = [
"futures-lite",
"log",
"mac-notification-sys",
"serde",
"tauri-winrt-notification",
"zbus",
]
[[package]]
name = "num-bigint-dig"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82c79c15c05d4bf82b6f5ef163104cc81a760d8e874d38ac50ab67c8877b647b"
dependencies = [
"byteorder",
"lazy_static",
"libm",
"num-integer",
@@ -3444,9 +3465,9 @@ dependencies = [
[[package]]
name = "potential_utf"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
dependencies = [
"zerovec",
]
@@ -3977,9 +3998,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.23.34"
version = "0.23.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7"
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
dependencies = [
"once_cell",
"ring",
@@ -4001,9 +4022,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
version = "0.103.7"
version = "0.103.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf"
checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
dependencies = [
"ring",
"rustls-pki-types",
@@ -4069,9 +4090,9 @@ dependencies = [
[[package]]
name = "schemars"
version = "1.0.4"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
checksum = "1317c3bf3e7df961da95b0a56a172a02abead31276215a0497241a7624b487ce"
dependencies = [
"dyn-clone",
"ref-cast",
@@ -4273,7 +4294,7 @@ dependencies = [
"indexmap 1.9.3",
"indexmap 2.12.0",
"schemars 0.9.0",
"schemars 1.0.4",
"schemars 1.0.5",
"serde_core",
"serde_json",
"serde_with_macros",
@@ -4941,9 +4962,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tauri"
version = "2.9.1"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9871670c6711f50fddd4e20350be6b9dd6e6c2b5d77d8ee8900eb0d58cd837a"
checksum = "8bceb52453e507c505b330afe3398510e87f428ea42b6e76ecb6bd63b15965b5"
dependencies = [
"anyhow",
"bytes",
@@ -5125,6 +5146,25 @@ dependencies = [
"url",
]
[[package]]
name = "tauri-plugin-notification"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01fc2c5ff41105bd1f7242d8201fdf3efd70749b82fa013a17f2126357d194cc"
dependencies = [
"log",
"notify-rust",
"rand 0.9.2",
"serde",
"serde_json",
"serde_repr",
"tauri",
"tauri-plugin",
"thiserror 2.0.17",
"time",
"url",
]
[[package]]
name = "tauri-plugin-opener"
version = "2.5.2"
@@ -5362,6 +5402,18 @@ dependencies = [
"toml 0.9.8",
]
[[package]]
name = "tauri-winrt-notification"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9"
dependencies = [
"quick-xml 0.37.5",
"thiserror 2.0.17",
"windows",
"windows-version",
]
[[package]]
name = "tempfile"
version = "3.23.0"
@@ -5473,9 +5525,9 @@ dependencies = [
[[package]]
name = "tinystr"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
dependencies = [
"displaydoc",
"zerovec",
@@ -5570,9 +5622,9 @@ dependencies = [
[[package]]
name = "tokio-util"
version = "0.7.16"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594"
dependencies = [
"bytes",
"futures-core",
@@ -5883,24 +5935,24 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]]
name = "unicode-ident"
version = "1.0.20"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unicode-normalization"
version = "0.1.24"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-properties"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
[[package]]
name = "unicode-segmentation"
@@ -5970,9 +6022,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version-compare"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e"
[[package]]
name = "version_check"
@@ -6057,9 +6109,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
[[package]]
name = "wasm-bindgen"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d"
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
dependencies = [
"cfg-if",
"once_cell",
@@ -6068,25 +6120,11 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn 2.0.108",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.54"
version = "0.4.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c"
checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
dependencies = [
"cfg-if",
"js-sys",
@@ -6097,9 +6135,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119"
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -6107,22 +6145,22 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7"
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn 2.0.108",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
dependencies = [
"unicode-ident",
]
@@ -6215,9 +6253,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.81"
version = "0.3.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120"
checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -6279,9 +6317,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8"
checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e"
dependencies = [
"rustls-pki-types",
]
@@ -6904,9 +6942,9 @@ dependencies = [
[[package]]
name = "writeable"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
[[package]]
name = "wry"
@@ -7003,11 +7041,10 @@ dependencies = [
[[package]]
name = "yoke"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
dependencies = [
"serde",
"stable_deref_trait",
"yoke-derive",
"zerofrom",
@@ -7015,9 +7052,9 @@ dependencies = [
[[package]]
name = "yoke-derive"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [
"proc-macro2",
"quote",
@@ -7136,9 +7173,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
[[package]]
name = "zerotrie"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
dependencies = [
"displaydoc",
"yoke",
@@ -7147,9 +7184,9 @@ dependencies = [
[[package]]
name = "zerovec"
version = "0.11.4"
version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
dependencies = [
"yoke",
"zerofrom",
@@ -7158,9 +7195,9 @@ dependencies = [
[[package]]
name = "zerovec-derive"
version = "0.11.1"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -1,6 +1,6 @@
[package]
name = "neodlp"
version = "0.3.2"
version = "0.3.4"
description = "NeoDLP"
authors = ["neosubhamoy <hey@neosubhamoy.com>"]
edition = "2021"
@@ -38,6 +38,7 @@ tauri-plugin-dialog = "2"
tauri-plugin-sql = { version = "2", features = ["sqlite"] }
tauri-plugin-process = "2"
tauri-plugin-clipboard-manager = "2"
tauri-plugin-notification = "2"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-single-instance = "2"

View File

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9397aac0de54c8c15b8166486eb80bfe27937bd6d6b6af4bb8383b155213bec1
size 6100888

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cca868da48a85c13a56ccac4dfa8c098f7ed799786a9eaf88248221dbb785bb9
size 8089088

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:36f66dab69edcc44255d0dba90c93f5aa4a304ec60c7136d8c279dfc89c23e1d
size 9666624

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b2243469ad3e5d874a2ccf87d3375ea6566c65b9aeae7154de7ad4dd403ef23d
size 91664944

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f13fc741f238849e8c2d48587ae4eced59abec6864b05b618feb5dc28168baff
size 103329904

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:30c6df2176d096fafbdc0f049a68d4a4466360fd8f8daf698d3fc406b0f7a5c7
size 102795504

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9037f4f141020246aac5f65336cda8127808d644a391df2502f76ef7ea3bdefb
size 117761496

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d96ceee08834553afb6d6cc6bc76cc3120ce765fe309ce1813b0dd1428c0bce9
size 113570336

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7717da6f1d21ec928aba5421f3ca83eddba63f6602e80a14901a2935982bf2f0
size 80129848

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8f0364b1e3db45af96ca1149bc76b6593713446dff28458681302861214a2ca5
size 152316736

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7717da6f1d21ec928aba5421f3ca83eddba63f6602e80a14901a2935982bf2f0
size 80129848

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1df43d5ee4c7ef9379f29fdddd9f7c538f6362de478ed4883ac566ad0dd65166
size 190388224

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3e3b84c425dd3c9f3b88712df0a3cf3ea844fb5968f15ed05eae63a0c2068fc7
size 191335144

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:90cae105568f54d029fbaacf25a4879f44b25aaa32fa2ba369696dfeac00d6c9
size 79947928

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:265c8a8a5b386970facc84e54cb3bfb72579d6729ce0d9b9a64d1ae4864c1274
size 152125760

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:90cae105568f54d029fbaacf25a4879f44b25aaa32fa2ba369696dfeac00d6c9
size 79947928

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:19208c2236b754cd359f6397ea1202521d961bba586c2434a0c99d056281aa87
size 190191104

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f8d7c94d5f600f8acd3555ebb64ce87a410dca9a84bb4ec586ba2c76cb594fdd
size 191123432

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4b8c840bf89c4428ada0c79bbae63e300d889c15efaf09321d42f502689bc5ed
size 35764384

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:59de22585cc971159674d797a2e094fb0c05a9238bbb8d3f7120f4867dfc699f
size 37285184

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4b8c840bf89c4428ada0c79bbae63e300d889c15efaf09321d42f502689bc5ed
size 35764384

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2f7446c110e4d2ccad95338871cd82d60354a85b82cfe1bc776b67b0deb8db8a
size 18344563

View File

@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d960d82b390bf63f79863d0a7b51df638ffc5d31e93aae42ba8bcf35927d94a0
size 37600736

View File

@@ -24,6 +24,7 @@
"process:default",
"clipboard-manager:allow-read-text",
"clipboard-manager:allow-write-text",
"notification:default",
{
"identifier": "opener:allow-open-path",
"allow": [

View File

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

View File

View File

@@ -174,6 +174,16 @@ fn get_config_file_path() -> Result<String, String> {
}
}
#[tauri::command]
fn get_current_app_path() -> Result<String, String> {
let exe_path = std::env::current_exe().map_err(|e| e.to_string())?;
Ok(exe_path
.parent()
.ok_or("Failed to get parent directory")?
.to_string_lossy()
.into_owned())
}
#[tauri::command]
async fn update_config(
new_config: Config,
@@ -487,6 +497,7 @@ pub async fn run() {
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_clipboard_manager::init())
.plugin(tauri_plugin_notification::init())
.manage(ImageCache(StdMutex::new(HashMap::new())))
.manage(websocket_state.clone())
.setup(move |app| {
@@ -588,6 +599,7 @@ pub async fn run() {
reset_config,
get_config_file_path,
restart_websocket_server,
get_current_app_path,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");

View File

@@ -2,7 +2,7 @@
"$schema": "https://schema.tauri.app/config/2",
"productName": "NeoDLP",
"mainBinaryName": "neodlp",
"version": "0.3.2",
"version": "0.3.4",
"identifier": "com.neosubhamoy.neodlp",
"build": {
"beforeDevCommand": "npm run dev",

View File

@@ -1,8 +1,8 @@
{
"identifier": "com.neosubhamoy.neodlp",
"build": {
"beforeDevCommand": "cargo build --target=aarch64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && node scripts/chmod.js && npm run dev",
"beforeBuildCommand": "cargo build --release --target=aarch64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && node scripts/chmod.js && npm run build",
"beforeDevCommand": "cargo build --target=aarch64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && npm run dev",
"beforeBuildCommand": "cargo build --release --target=aarch64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && npm run build",
"devUrl": "http://localhost:1420",
"frontendDist": "../dist"
},

View File

@@ -1,8 +1,8 @@
{
"identifier": "com.neosubhamoy.neodlp",
"build": {
"beforeDevCommand": "cargo build --target=x86_64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && node scripts/chmod.js && npm run dev",
"beforeBuildCommand": "cargo build --release --target=x86_64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && node scripts/chmod.js && npm run build",
"beforeDevCommand": "cargo build --target=x86_64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && npm run dev",
"beforeBuildCommand": "cargo build --release --target=x86_64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && npm run build",
"devUrl": "http://localhost:1420",
"frontendDist": "../dist"
},

View File

@@ -1,8 +1,8 @@
{
"identifier": "com.neosubhamoy.neodlp",
"build": {
"beforeDevCommand": "cargo build --target=aarch64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && node scripts/chmod.js && npm run dev",
"beforeBuildCommand": "cargo build --release --target=aarch64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && node scripts/chmod.js && npm run build",
"beforeDevCommand": "cargo build --target=aarch64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && npm run dev",
"beforeBuildCommand": "cargo build --release --target=aarch64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && npm run build",
"devUrl": "http://localhost:1420",
"frontendDist": "../dist"
},

View File

@@ -1,8 +1,8 @@
{
"identifier": "com.neosubhamoy.neodlp",
"build": {
"beforeDevCommand": "cargo build --target=x86_64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && node scripts/chmod.js && npm run dev",
"beforeBuildCommand": "cargo build --release --target=x86_64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && node scripts/chmod.js && npm run build",
"beforeDevCommand": "cargo build --target=x86_64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && npm run dev",
"beforeBuildCommand": "cargo build --release --target=x86_64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && npm run build",
"devUrl": "http://localhost:1420",
"frontendDist": "../dist"
},

View File

@@ -29,6 +29,7 @@ import { toast } from "sonner";
import { useLogger } from "@/helpers/use-logger";
import { DownloadConfiguration } from "@/types/settings";
import { ulid } from "ulid";
import { sendNotification } from '@tauri-apps/plugin-notification';
export default function App({ children }: { children: React.ReactNode }) {
const { data: downloadStates, isSuccess: isSuccessFetchingDownloadStates } = useFetchAllDownloadStates();
@@ -71,6 +72,7 @@ export default function App({ children }: { children: React.ReactNode }) {
const ALWAYS_REENCODE_VIDEO = useSettingsPageStatesStore(state => state.settings.always_reencode_video);
const EMBED_VIDEO_METADATA = useSettingsPageStatesStore(state => state.settings.embed_video_metadata);
const EMBED_AUDIO_METADATA = useSettingsPageStatesStore(state => state.settings.embed_audio_metadata);
const EMBED_VIDEO_THUMBNAIL = useSettingsPageStatesStore(state => state.settings.embed_video_thumbnail);
const EMBED_AUDIO_THUMBNAIL = useSettingsPageStatesStore(state => state.settings.embed_audio_thumbnail);
const USE_COOKIES = useSettingsPageStatesStore(state => state.settings.use_cookies);
const IMPORT_COOKIES_FROM = useSettingsPageStatesStore(state => state.settings.import_cookies_from);
@@ -92,6 +94,8 @@ export default function App({ children }: { children: React.ReactNode }) {
const LOG_VERBOSE = useSettingsPageStatesStore(state => state.settings.log_verbose);
const LOG_WARNING = useSettingsPageStatesStore(state => state.settings.log_warning);
const LOG_PROGRESS = useSettingsPageStatesStore(state => state.settings.log_progress);
const ENABLE_NOTIFICATIONS = useSettingsPageStatesStore(state => state.settings.enable_notifications);
const DOWNLOAD_COMPLETION_NOTIFICATION = useSettingsPageStatesStore(state => state.settings.download_completion_notification);
const isErrored = useDownloaderPageStatesStore((state) => state.isErrored);
const isErrorExpected = useDownloaderPageStatesStore((state) => state.isErrorExpected);
@@ -125,6 +129,7 @@ export default function App({ children }: { children: React.ReactNode }) {
const isProcessingQueueRef = useRef(false);
const lastProcessedDownloadIdRef = useRef<string | null>(null);
const hasRunYtDlpAutoUpdateRef = useRef(false);
const hasRunAppUpdateCheckRef = useRef(false);
const isRegisteredToMacOsRef = useRef(false);
const fetchVideoMetadata = async (url: string, formatId?: string, playlistIndex?: string, selectedSubtitles?: string | null, resumeState?: DownloadState, downloadConfig?: DownloadConfiguration): Promise<RawVideoInfo | null> => {
@@ -304,7 +309,7 @@ export default function App({ children }: { children: React.ReactNode }) {
];
if (currentPlatform === 'macos') {
args.push('--ffmpeg-location', '/Applications/NeoDLP.app/Contents/MacOS');
args.push('--ffmpeg-location', '/Applications/NeoDLP.app/Contents/MacOS', '--js-runtimes', 'deno:/Applications/NeoDLP.app/Contents/MacOS/deno');
}
if (!DEBUG_MODE || (DEBUG_MODE && !LOG_WARNING)) {
@@ -374,20 +379,26 @@ export default function App({ children }: { children: React.ReactNode }) {
let embedMetadata = 0;
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && (downloadConfig.embed_metadata || resumeState?.embed_metadata || EMBED_VIDEO_METADATA || EMBED_AUDIO_METADATA)) {
const shouldEmbedForVideo = (fileType === 'video+audio' || fileType === 'video') && (downloadConfig.embed_metadata || resumeState?.embed_metadata || (EMBED_VIDEO_METADATA && downloadConfig.embed_metadata === null));
const shouldEmbedForAudio = fileType === 'audio' && (downloadConfig.embed_metadata || resumeState?.embed_metadata || (EMBED_AUDIO_METADATA && downloadConfig.embed_metadata === null));
const shouldEmbedForUnknown = fileType === 'unknown' && (downloadConfig.embed_metadata || resumeState?.embed_metadata);
const shouldEmbedMetaForVideo = (fileType === 'video+audio' || fileType === 'video') && (downloadConfig.embed_metadata || resumeState?.embed_metadata || (EMBED_VIDEO_METADATA && downloadConfig.embed_metadata === null));
const shouldEmbedMetaForAudio = fileType === 'audio' && (downloadConfig.embed_metadata || resumeState?.embed_metadata || (EMBED_AUDIO_METADATA && downloadConfig.embed_metadata === null));
const shouldEmbedMetaForUnknown = fileType === 'unknown' && (downloadConfig.embed_metadata || resumeState?.embed_metadata);
if (shouldEmbedForUnknown || shouldEmbedForVideo || shouldEmbedForAudio) {
if (shouldEmbedMetaForUnknown || shouldEmbedMetaForVideo || shouldEmbedMetaForAudio) {
embedMetadata = 1;
args.push('--embed-metadata');
}
}
let embedThumbnail = 0;
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail || (fileType === 'audio' && EMBED_AUDIO_THUMBNAIL && downloadConfig.embed_thumbnail === null))) {
embedThumbnail = 1;
args.push('--embed-thumbnail');
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail || EMBED_VIDEO_THUMBNAIL || EMBED_AUDIO_THUMBNAIL)) {
const shouldEmbedThumbForVideo = (fileType === 'video+audio' || fileType === 'video') && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail || (EMBED_VIDEO_THUMBNAIL && downloadConfig.embed_thumbnail === null));
const shouldEmbedThumbForAudio = fileType === 'audio' && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail || (EMBED_AUDIO_THUMBNAIL && downloadConfig.embed_thumbnail === null));
const shouldEmbedThumbForUnknown = fileType === 'unknown' && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail);
if (shouldEmbedThumbForUnknown || shouldEmbedThumbForVideo || shouldEmbedThumbForAudio) {
embedThumbnail = 1;
args.push('--embed-thumbnail');
}
}
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && USE_PROXY && PROXY_URL) {
@@ -416,13 +427,13 @@ export default function App({ children }: { children: React.ReactNode }) {
let sponsorblockRemove = null;
let sponsorblockMark = null;
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && (USE_SPONSORBLOCK || (resumeState?.sponsorblock_remove || resumeState?.sponsorblock_mark))) {
if (SPONSORBLOCK_MODE === 'remove' || resumeState?.sponsorblock_remove) {
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && ((downloadConfig.sponsorblock && downloadConfig.sponsorblock !== 'auto') || resumeState?.sponsorblock_remove || resumeState?.sponsorblock_mark || USE_SPONSORBLOCK)) {
if (downloadConfig?.sponsorblock === 'remove' || resumeState?.sponsorblock_remove || (SPONSORBLOCK_MODE === 'remove' && !downloadConfig.sponsorblock)) {
sponsorblockRemove = resumeState?.sponsorblock_remove || (SPONSORBLOCK_REMOVE === 'custom' ? (
SPONSORBLOCK_REMOVE_CATEGORIES.length > 0 ? SPONSORBLOCK_REMOVE_CATEGORIES.join(',') : 'default'
) : (SPONSORBLOCK_REMOVE));
args.push('--sponsorblock-remove', sponsorblockRemove);
} else if (SPONSORBLOCK_MODE === 'mark' || resumeState?.sponsorblock_mark) {
} else if (downloadConfig?.sponsorblock === 'mark' || resumeState?.sponsorblock_mark || (SPONSORBLOCK_MODE === 'mark' && !downloadConfig.sponsorblock)) {
sponsorblockMark = resumeState?.sponsorblock_mark || (SPONSORBLOCK_MARK === 'custom' ? (
SPONSORBLOCK_MARK_CATEGORIES.length > 0 ? SPONSORBLOCK_MARK_CATEGORIES.join(',') : 'default'
) : (SPONSORBLOCK_MARK));
@@ -541,8 +552,8 @@ export default function App({ children }: { children: React.ReactNode }) {
const downloadedFileExt = downloadFilePath.split('.').pop();
// Update completion status after a short delay to ensure database states are propagated correctly
console.log(`Download completed with ID: ${downloadId}, updating filepath and status after 2s delay...`);
setTimeout(() => {
console.log(`Download completed with ID: ${downloadId}, updating filepath and status after 1.5s delay...`);
setTimeout(async () => {
LOG.info('NEODLP', `yt-dlp download completed with id: ${downloadId}`);
downloadFilePathUpdater.mutate({ download_id: downloadId, filepath: downloadFilePath as string, ext: downloadedFileExt as string }, {
onSuccess: (data) => {
@@ -563,7 +574,18 @@ export default function App({ children }: { children: React.ReactNode }) {
console.error("Failed to update download status:", error);
}
});
}, 2000);
toast.success("Download Completed", {
description: `The download for "${videoMetadata.title}" has completed successfully.`,
});
if (ENABLE_NOTIFICATIONS && DOWNLOAD_COMPLETION_NOTIFICATION) {
sendNotification({
title: "Download Completed",
body: `The download for "${videoMetadata.title}" has completed successfully.`,
});
}
}, 1500);
}
}
});
@@ -742,6 +764,7 @@ export default function App({ children }: { children: React.ReactNode }) {
output_format: null,
embed_metadata: null,
embed_thumbnail: null,
sponsorblock: null,
custom_command: null
},
downloadState.subtitle_id,
@@ -844,6 +867,7 @@ export default function App({ children }: { children: React.ReactNode }) {
output_format: null,
embed_metadata: null,
embed_thumbnail: null,
sponsorblock: null,
custom_command: null
},
downloadToStart.subtitle_id,
@@ -869,13 +893,6 @@ export default function App({ children }: { children: React.ReactNode }) {
}
}
// Check for App updates
useEffect(() => {
checkForAppUpdate().catch((error) => {
console.error("Error checking for app update:", error);
});
}, []);
// Prevent app from closing
useEffect(() => {
const handleCloseRequested = (event: any) => {
@@ -1025,6 +1042,24 @@ export default function App({ children }: { children: React.ReactNode }) {
fetchYtDlpVersion();
}, [ytDlpVersion, setYtDlpVersion]);
// Check for app update
useEffect(() => {
// Only run once when both settings and KV pairs are loaded
if (!isSettingsStatePropagated || !isKvPairsStatePropagated) {
console.log("Skipping app update check, waiting for configs to load...");
return;
}
// Skip if we've already run the update check once
if (hasRunAppUpdateCheckRef.current) {
console.log("App update check already performed in this session, skipping");
return;
}
hasRunAppUpdateCheckRef.current = true;
checkForAppUpdate().catch((error) => {
console.error("Error checking for app update:", error);
});
}, [isSettingsStatePropagated, isKvPairsStatePropagated]);
// Check for yt-dlp auto-update
useEffect(() => {
// Only run once when both settings and KV pairs are loaded
@@ -1047,7 +1082,6 @@ export default function App({ children }: { children: React.ReactNode }) {
const YTDLP_UPDATE_INTERVAL = 86400000 // 24H;
if (YTDLP_AUTO_UPDATE && (ytDlpUpdateLastCheck === null || currentTimestamp - ytDlpUpdateLastCheck > YTDLP_UPDATE_INTERVAL)) {
console.log("Running auto-update for yt-dlp...");
LOG.info('NEODLP', 'Updating yt-dlp to latest version (triggered because auto-update is enabled)');
updateYtDlp();
} else {
console.log("Skipping yt-dlp auto-update, either disabled or recently updated.");

View File

@@ -1,12 +1,18 @@
import { config } from "@/config";
import { check as checkAppUpdate, Update } from "@tauri-apps/plugin-updater";
import { relaunch as relaunchApp } from "@tauri-apps/plugin-process";
import { useSettingsPageStatesStore } from "@/services/store";
import { useLogger } from "@/helpers/use-logger";
import { sendNotification } from '@tauri-apps/plugin-notification';
export default function useAppUpdater() {
const setIsCheckingAppUpdate = useSettingsPageStatesStore(state => state.setIsCheckingAppUpdate);
const setAppUpdate = useSettingsPageStatesStore(state => state.setAppUpdate);
const setIsUpdating = useSettingsPageStatesStore(state => state.setIsUpdatingApp);
const setDownloadProgress = useSettingsPageStatesStore(state => state.setAppUpdateDownloadProgress);
const enableNotifications = useSettingsPageStatesStore(state => state.settings.enable_notifications);
const updateNotification = useSettingsPageStatesStore(state => state.settings.update_notification);
const LOG = useLogger();
const checkForAppUpdate = async () => {
setIsCheckingAppUpdate(true);
@@ -15,6 +21,13 @@ export default function useAppUpdater() {
if (update) {
setAppUpdate(update);
console.log(`app update available v${update.version}`);
LOG.info('NEODLP', `App update available v${update.version}`);
if (enableNotifications && updateNotification) {
sendNotification({
title: `Update Available (v${update.version})`,
body: `A newer version of ${config.appName} is available. Please update to the latest version for the best experience`,
});
}
}
} catch (error) {
console.error(error);
@@ -25,6 +38,7 @@ export default function useAppUpdater() {
const downloadAndInstallAppUpdate = async (update: Update) => {
setIsUpdating(true);
LOG.info('NEODLP', `Downloading and installing app update v${update.version}`);
let downloaded = 0;
let contentLength: number | undefined = 0;
await update.downloadAndInstall((event) => {
@@ -52,4 +66,4 @@ export default function useAppUpdater() {
checkForAppUpdate,
downloadAndInstallAppUpdate
}
}
}

View File

@@ -1,7 +1,11 @@
import { useSettingsPageStatesStore } from "@/services/store";
import { useKvPairs } from "@/helpers/use-kvpairs";
import { Command } from "@tauri-apps/plugin-shell";
import { invoke } from "@tauri-apps/api/core";
import { join } from "@tauri-apps/api/path";
import { platform } from "@tauri-apps/plugin-os";
import { useLogger } from "@/helpers/use-logger";
import { toast } from "sonner";
export function useYtDlpUpdater() {
const { saveKvPair } = useKvPairs();
@@ -9,26 +13,53 @@ export function useYtDlpUpdater() {
const setIsUpdatingYtDlp = useSettingsPageStatesStore((state) => state.setIsUpdatingYtDlp);
const setYtDlpVersion = useSettingsPageStatesStore((state) => state.setYtDlpVersion);
const currentPlatform = platform();
const LOG = useLogger();
const updateYtDlp = async () => {
const CURRENT_TIMESTAMP = Date.now();
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 output = await command.execute();
if (output.code === 0) {
console.log("yt-dlp updated successfully:", output.stdout);
LOG.info('NEODLP', "yt-dlp updated successfully");
saveKvPair('ytdlp_update_last_check', CURRENT_TIMESTAMP);
setYtDlpVersion(null);
toast.success("Update successful", { description: "yt-dlp has been updated successfully." });
} else {
if (currentPlatform === 'windows') {
LOG.warning('NEODLP', "yt-dlp update failed! Now, attempting with elevated privileges.");
const appPath = await invoke<string>('get_current_app_path');
const ytdlpPath = await join(appPath, 'yt-dlp.exe');
const elevateCommand = Command.create('powershell', ['Start-Process', `"${ytdlpPath}"`, '-ArgumentList', `"--update-to ${ytDlpUpdateChannel}"`, '-Verb', 'RunAs', '-Wait', '-WindowStyle', 'Hidden']);
const elevateOutput = await elevateCommand.execute();
if (elevateOutput.code === 0) {
console.log("yt-dlp updated successfully with elevation:", elevateOutput.stdout);
LOG.info('NEODLP', "yt-dlp updated successfully with elevation");
saveKvPair('ytdlp_update_last_check', CURRENT_TIMESTAMP);
setYtDlpVersion(null);
toast.success("Update successful", { description: "yt-dlp has been updated successfully." });
} else {
console.error("Failed to update yt-dlp with elevation:", elevateOutput.stderr);
LOG.error('NEODLP', `Failed to update yt-dlp with elevation: ${elevateOutput.stderr}`);
toast.error("Update failed", { description: "Failed to update yt-dlp." });
}
return;
}
console.error("Failed to update yt-dlp:", output.stderr);
LOG.error('NEODLP', `Failed to update yt-dlp: ${output.stderr}`);
toast.error("Update failed", { description: "Failed to update yt-dlp." });
}
} catch (e) {
console.error('Failed to update yt-dlp:', e);
LOG.error('NEODLP', `Exception while updating yt-dlp: ${e}`);
toast.error("Update failed", { description: "An error occurred while updating yt-dlp." });
} finally {
setIsUpdatingYtDlp(false);
}
}
return { updateYtDlp };
}
}

View File

@@ -80,6 +80,7 @@ export default function DownloaderPage() {
const audioFormat = useSettingsPageStatesStore(state => state.settings.audio_format);
const embedVideoMetadata = useSettingsPageStatesStore(state => state.settings.embed_video_metadata);
const embedAudioMetadata = useSettingsPageStatesStore(state => state.settings.embed_audio_metadata);
const embedVideoThumbnail = useSettingsPageStatesStore(state => state.settings.embed_video_thumbnail);
const embedAudioThumbnail = useSettingsPageStatesStore(state => state.settings.embed_audio_thumbnail);
const useCustomCommands = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
const customCommands = useSettingsPageStatesStore(state => state.settings.custom_commands);
@@ -496,6 +497,7 @@ export default function DownloaderPage() {
setDownloadConfigurationKey('output_format', null);
setDownloadConfigurationKey('embed_metadata', null);
setDownloadConfigurationKey('embed_thumbnail', null);
setDownloadConfigurationKey('sponsorblock', null);
}}
>
<div className="flex items-center justify-between">
@@ -545,6 +547,7 @@ export default function DownloaderPage() {
setDownloadConfigurationKey('output_format', null);
setDownloadConfigurationKey('embed_metadata', null);
setDownloadConfigurationKey('embed_thumbnail', null);
setDownloadConfigurationKey('sponsorblock', null);
}}
>
<p className="text-xs">Suggested</p>
@@ -648,6 +651,7 @@ export default function DownloaderPage() {
setDownloadConfigurationKey('output_format', null);
setDownloadConfigurationKey('embed_metadata', null);
setDownloadConfigurationKey('embed_thumbnail', null);
setDownloadConfigurationKey('sponsorblock', null);
}}
>
{videoOnlyFormats && videoOnlyFormats.length > 0 && audioOnlyFormats && audioOnlyFormats.length > 0 && (
@@ -672,6 +676,7 @@ export default function DownloaderPage() {
setDownloadConfigurationKey('output_format', null);
setDownloadConfigurationKey('embed_metadata', null);
setDownloadConfigurationKey('embed_thumbnail', null);
setDownloadConfigurationKey('sponsorblock', null);
}}
>
{audioOnlyFormats && audioOnlyFormats.length > 0 && videoOnlyFormats && videoOnlyFormats.length > 0 && (
@@ -1114,6 +1119,29 @@ export default function DownloaderPage() {
</RadioGroup>
)}
</div>
<div className="sponsorblock">
<Label className="text-xs my-3">Sponsorblock Mode</Label>
<RadioGroup
orientation="horizontal"
className="flex items-center gap-4 flex-wrap"
value={downloadConfiguration.sponsorblock ?? 'auto'}
onValueChange={(value) => setDownloadConfigurationKey('sponsorblock', value)}
disabled={useCustomCommands}
>
<div className="flex items-center gap-3">
<RadioGroupItem value="auto" id="sb-auto" />
<Label htmlFor="sb-auto">Follow Settings</Label>
</div>
<div className="flex items-center gap-3">
<RadioGroupItem value="remove" id="sb-remove" />
<Label htmlFor="sb-remove">Remove</Label>
</div>
<div className="flex items-center gap-3">
<RadioGroupItem value="mark" id="sb-mark" />
<Label htmlFor="sb-mark">Mark</Label>
</div>
</RadioGroup>
</div>
<div className="embeding-options">
<Label className="text-xs my-3">Embeding Options</Label>
<div className="flex items-center space-x-2 mt-3">
@@ -1128,7 +1156,7 @@ export default function DownloaderPage() {
<div className="flex items-center space-x-2 mt-3">
<Switch
id="embed-thumbnail"
checked={downloadConfiguration.embed_thumbnail !== null ? downloadConfiguration.embed_thumbnail : (selectedFormatFileType && (selectedFormatFileType === 'video' || selectedFormatFileType === 'video+audio')) || activeDownloadModeTab === 'combine' ? false : selectedFormatFileType && selectedFormatFileType === 'audio' ? embedAudioThumbnail : false}
checked={downloadConfiguration.embed_thumbnail !== null ? downloadConfiguration.embed_thumbnail : (selectedFormatFileType && (selectedFormatFileType === 'video' || selectedFormatFileType === 'video+audio')) || activeDownloadModeTab === 'combine' ? embedVideoThumbnail : selectedFormatFileType && selectedFormatFileType === 'audio' ? embedAudioThumbnail : false}
onCheckedChange={(checked) => setDownloadConfigurationKey('embed_thumbnail', checked)}
disabled={useCustomCommands}
/>

View File

@@ -7,7 +7,7 @@ import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import { ArrowDownToLine, ArrowRight, BrushCleaning, Bug, Cookie, EthernetPort, ExternalLink, FileVideo, Folder, FolderOpen, Info, Loader2, LucideIcon, Monitor, Moon, Radio, RotateCcw, RotateCw, ShieldMinus, SquareTerminal, Sun, Terminal, Trash, TriangleAlert, WandSparkles, Wifi, Wrench } from "lucide-react";
import { ArrowDownToLine, ArrowRight, BellRing, BrushCleaning, Bug, Cookie, EthernetPort, ExternalLink, FileVideo, Folder, FolderOpen, Info, Loader2, LucideIcon, Monitor, Moon, Radio, RotateCcw, RotateCw, ShieldMinus, SquareTerminal, Sun, Terminal, Trash, TriangleAlert, WandSparkles, Wifi, Wrench } from "lucide-react";
import { cn } from "@/lib/utils";
import { useEffect } from "react";
import { useTheme } from "@/providers/themeProvider";
@@ -30,6 +30,7 @@ import { formatSpeed, generateID } from "@/utils";
import { ToggleGroup, ToggleGroupItem } from "@/components/custom/legacyToggleGroup";
import { Textarea } from "@/components/ui/textarea";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { isPermissionGranted, requestPermission } from '@tauri-apps/plugin-notification';
const websocketPortSchema = z.object({
port: z.coerce.number<number>({
@@ -106,6 +107,7 @@ export default function SettingsPage() {
const alwaysReencodeVideo = useSettingsPageStatesStore(state => state.settings.always_reencode_video);
const embedVideoMetadata = useSettingsPageStatesStore(state => state.settings.embed_video_metadata);
const embedAudioMetadata = useSettingsPageStatesStore(state => state.settings.embed_audio_metadata);
const embedVideoThumbnail = useSettingsPageStatesStore(state => state.settings.embed_video_thumbnail);
const embedAudioThumbnail = useSettingsPageStatesStore(state => state.settings.embed_audio_thumbnail);
const useCookies = useSettingsPageStatesStore(state => state.settings.use_cookies);
const importCookiesFrom = useSettingsPageStatesStore(state => state.settings.import_cookies_from);
@@ -127,6 +129,9 @@ export default function SettingsPage() {
const logVerbose = useSettingsPageStatesStore(state => state.settings.log_verbose);
const logWarning = useSettingsPageStatesStore(state => state.settings.log_warning);
const logProgress = useSettingsPageStatesStore(state => state.settings.log_progress);
const enableNotifications = useSettingsPageStatesStore(state => state.settings.enable_notifications);
const updateNotification = useSettingsPageStatesStore(state => state.settings.update_notification);
const downloadCompletionNotification = useSettingsPageStatesStore(state => state.settings.download_completion_notification);
const websocketPort = useSettingsPageStatesStore(state => state.settings.websocket_port);
const isChangingWebSocketPort = useSettingsPageStatesStore(state => state.isChangingWebSocketPort);
@@ -524,6 +529,11 @@ export default function SettingsPage() {
value="sponsorblock"
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground justify-start px-3 py-1.5 gap-2"
><ShieldMinus className="size-4" /> Sponsorblock</TabsTrigger>
<TabsTrigger
key="notifications"
value="notifications"
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground justify-start px-3 py-1.5 gap-2"
><BellRing className="size-4" /> Notifications</TabsTrigger>
<TabsTrigger
key="commands"
value="commands"
@@ -536,7 +546,7 @@ export default function SettingsPage() {
><Bug className="size-4" /> Debug</TabsTrigger>
</TabsList>
<div className="min-h-full flex flex-col max-w-[55%] w-full border-l border-border pl-4">
<TabsContent key="general" value="general" className="flex flex-col gap-4 min-h-[385px]">
<TabsContent key="general" value="general" className="flex flex-col gap-4 min-h-[425px]">
<div className="max-parallel-downloads">
<h3 className="font-semibold">Max Parallel Downloads</h3>
<p className="text-xs text-muted-foreground mb-3">Set maximum number of allowed parallel downloads</p>
@@ -592,7 +602,7 @@ export default function SettingsPage() {
/>
</div>
</TabsContent>
<TabsContent key="appearance" value="appearance" className="flex flex-col gap-4 min-h-[385px]">
<TabsContent key="appearance" value="appearance" className="flex flex-col gap-4 min-h-[425px]">
<div className="app-theme">
<h3 className="font-semibold">Theme</h3>
<p className="text-xs text-muted-foreground mb-3">Choose app interface theme</p>
@@ -615,7 +625,7 @@ export default function SettingsPage() {
</div>
</div>
</TabsContent>
<TabsContent key="folders" value="folders" className="flex flex-col gap-4 min-h-[385px]">
<TabsContent key="folders" value="folders" className="flex flex-col gap-4 min-h-[425px]">
<div className="download-dir">
<h3 className="font-semibold">Download Folder</h3>
<p className="text-xs text-muted-foreground mb-3">Set default download folder (directory)</p>
@@ -705,7 +715,7 @@ export default function SettingsPage() {
</Form>
</div>
</TabsContent>
<TabsContent key="formats" value="formats" className="flex flex-col gap-4 min-h-[385px]">
<TabsContent key="formats" value="formats" className="flex flex-col gap-4 min-h-[425px]">
<div className="video-format">
<h3 className="font-semibold">Video Format</h3>
<p className="text-xs text-muted-foreground mb-3">Choose in which format the final video file will be saved</p>
@@ -773,8 +783,8 @@ export default function SettingsPage() {
/>
</div>
</TabsContent>
<TabsContent key="metadata" value="metadata" className="flex flex-col gap-4 min-h-[385px]">
<div className="embed-video-metadata">
<TabsContent key="metadata" value="metadata" className="flex flex-col gap-4 min-h-[425px]">
<div className="embed-metadata">
<h3 className="font-semibold">Embed Metadata</h3>
<p className="text-xs text-muted-foreground mb-3">Wheather to embed metadata in video/audio files (info, chapters)</p>
<div className="flex items-center space-x-2 mb-3">
@@ -796,18 +806,30 @@ export default function SettingsPage() {
<Label htmlFor="embed-audio-metadata">Audio</Label>
</div>
</div>
<div className="embed-audio-thumbnail">
<h3 className="font-semibold">Embed Thumbnail in Audio</h3>
<p className="text-xs text-muted-foreground mb-3">Wheather to embed thumbnail in audio files (as cover art)</p>
<Switch
id="embed-audio-thumbnail"
checked={embedAudioThumbnail}
onCheckedChange={(checked) => saveSettingsKey('embed_audio_thumbnail', checked)}
disabled={useCustomCommands}
/>
<div className="embed-thumbnail">
<h3 className="font-semibold">Embed Thumbnail</h3>
<p className="text-xs text-muted-foreground mb-3">Wheather to embed thumbnail in video/audio files (as cover art)</p>
<div className="flex items-center space-x-2 mb-3">
<Switch
id="embed-video-thumbnail"
checked={embedVideoThumbnail}
onCheckedChange={(checked) => saveSettingsKey('embed_video_thumbnail', checked)}
disabled={useCustomCommands}
/>
<Label htmlFor="embed-video-thumbnail">Video</Label>
</div>
<div className="flex items-center space-x-2">
<Switch
id="embed-audio-thumbnail"
checked={embedAudioThumbnail}
onCheckedChange={(checked) => saveSettingsKey('embed_audio_thumbnail', checked)}
disabled={useCustomCommands}
/>
<Label htmlFor="embed-audio-thumbnail">Audio</Label>
</div>
</div>
</TabsContent>
<TabsContent key="network" value="network" className="flex flex-col gap-4 min-h-[385px]">
<TabsContent key="network" value="network" className="flex flex-col gap-4 min-h-[425px]">
<div className="proxy">
<h3 className="font-semibold">Proxy</h3>
<p className="text-xs text-muted-foreground mb-3">Use proxy for downloads, Unblocks blocked sites in your region (download speed may affect, some sites may not work)</p>
@@ -923,7 +945,7 @@ export default function SettingsPage() {
<Label className="text-xs text-muted-foreground">(Forced: {forceInternetProtocol === "ipv4" ? 'IPv4' : 'IPv6'}, Status: {useForceInternetProtocol && !useCustomCommands ? 'Enabled' : 'Disabled'})</Label>
</div>
</TabsContent>
<TabsContent key="cookies" value="cookies" className="flex flex-col gap-4 min-h-[385px]">
<TabsContent key="cookies" value="cookies" className="flex flex-col gap-4 min-h-[425px]">
<div className="cookies">
<h3 className="font-semibold">Cookies</h3>
<p className="text-xs text-muted-foreground mb-3">Use cookies to access exclusive/private (login-protected) contents from sites (use wisely, over-use can even block/ban your account)</p>
@@ -1012,7 +1034,7 @@ export default function SettingsPage() {
<Label className="text-xs text-muted-foreground">(Configured: {importCookiesFrom === "browser" ? 'Yes' : cookiesFile ? 'Yes' : 'No'}, From: {importCookiesFrom === "browser" ? 'Browser' : 'Text'}, Status: {useCookies && !useCustomCommands ? 'Enabled' : 'Disabled'})</Label>
</div>
</TabsContent>
<TabsContent key="sponsorblock" value="sponsorblock" className="flex flex-col gap-4 min-h-[385px]">
<TabsContent key="sponsorblock" value="sponsorblock" className="flex flex-col gap-4 min-h-[425px]">
<div className="sponsorblock">
<h3 className="font-semibold">Sponsor Block</h3>
<p className="text-xs text-muted-foreground mb-3">Use sponsorblock to remove/mark unwanted segments in videos (sponsorships, intros, outros, etc.)</p>
@@ -1048,7 +1070,7 @@ export default function SettingsPage() {
className="flex items-center gap-4"
value={sponsorblockRemove}
onValueChange={(value) => saveSettingsKey('sponsorblock_remove', value)}
disabled={!useSponsorblock || sponsorblockMode !== "remove" || useCustomCommands}
disabled={/*!useSponsorblock || sponsorblockMode !== "remove" ||*/ useCustomCommands}
>
<div className="flex items-center gap-3">
<RadioGroupItem value="default" id="sponsorblock-remove-default" />
@@ -1069,7 +1091,7 @@ export default function SettingsPage() {
className="flex flex-col items-start gap-2 mt-1"
value={sponsorblockRemove === "custom" ? sponsorblockRemoveCategories : sponsorblockRemove === "default" ? sponsorblockCategories.filter((cat) => cat.code !== 'poi_highlight' && cat.code !== 'filler').map((cat) => cat.code) : sponsorblockRemove === "all" ? sponsorblockCategories.filter((cat) => cat.code !== 'poi_highlight').map((cat) => cat.code) : []}
onValueChange={(value) => saveSettingsKey('sponsorblock_remove_categories', value)}
disabled={!useSponsorblock || sponsorblockMode !== "remove" || sponsorblockRemove !== "custom" || useCustomCommands}
disabled={/*!useSponsorblock || sponsorblockMode !== "remove" ||*/ sponsorblockRemove !== "custom" || useCustomCommands}
>
<div className="flex gap-2 flex-wrap items-center">
{sponsorblockCategories.map((category) => (
@@ -1095,7 +1117,7 @@ export default function SettingsPage() {
className="flex items-center gap-4"
value={sponsorblockMark}
onValueChange={(value) => saveSettingsKey('sponsorblock_mark', value)}
disabled={!useSponsorblock || sponsorblockMode !== "mark" || useCustomCommands}
disabled={/*!useSponsorblock || sponsorblockMode !== "mark" ||*/ useCustomCommands}
>
<div className="flex items-center gap-3">
<RadioGroupItem value="default" id="sponsorblock-mark-default" />
@@ -1116,7 +1138,7 @@ export default function SettingsPage() {
className="flex flex-col items-start gap-2 mt-1 mb-2"
value={sponsorblockMark === "custom" ? sponsorblockMarkCategories : sponsorblockMark === "default" ? sponsorblockCategories.map((cat) => cat.code) : sponsorblockMark === "all" ? sponsorblockCategories.map((cat) => cat.code) : []}
onValueChange={(value) => saveSettingsKey('sponsorblock_mark_categories', value)}
disabled={!useSponsorblock || sponsorblockMode !== "mark" || sponsorblockMark !== "custom" || useCustomCommands}
disabled={/*!useSponsorblock || sponsorblockMode !== "mark" ||*/ sponsorblockMark !== "custom" || useCustomCommands}
>
<div className="flex gap-2 flex-wrap items-center">
{sponsorblockCategories.map((category) => (
@@ -1136,7 +1158,56 @@ export default function SettingsPage() {
<Label className="text-xs text-muted-foreground">(Configured: {sponsorblockMode === "remove" && sponsorblockRemove === "custom" && sponsorblockRemoveCategories.length <= 0 ? 'No' : sponsorblockMode === "mark" && sponsorblockMark === "custom" && sponsorblockMarkCategories.length <= 0 ? 'No' : 'Yes'}, Mode: {sponsorblockMode === "remove" ? 'Remove' : 'Mark'}, Status: {useSponsorblock && !useCustomCommands ? 'Enabled' : 'Disabled'})</Label>
</div>
</TabsContent>
<TabsContent key="commands" value="commands" className="flex flex-col gap-4 min-h-[385px]">
<TabsContent key="notifications" value="notifications" className="flex flex-col gap-4 min-h-[425px]">
<div className="notifications">
<h3 className="font-semibold">Desktop Notifications</h3>
<p className="text-xs text-muted-foreground mb-3">Enable desktop notifications for app events (updates, download completions, etc.)</p>
<div className="flex items-center space-x-2 mb-4">
<Switch
id="enable-notifications"
checked={enableNotifications}
onCheckedChange={async (checked) => {
if (checked) {
const granted = await isPermissionGranted();
if (!granted) {
const permission = await requestPermission();
if (permission !== 'granted') {
toast.error("Notification Permission Denied", {
description: "You have denied the notification permission. Please enable it from your system settings to receive notifications.",
});
return;
}
}
}
saveSettingsKey('enable_notifications', checked)
}}
/>
<Label htmlFor="enable-notifications">Enable Notifications</Label>
</div>
<div className="flex flex-col gap-2 mt-5">
<Label className="text-xs mb-1">Notification Categories</Label>
<div className="flex items-center space-x-2 mb-1">
<Switch
id="update-notification"
checked={updateNotification}
onCheckedChange={(checked) => saveSettingsKey('update_notification', checked)}
disabled={!enableNotifications}
/>
<Label htmlFor="update-notification">App Updates</Label>
</div>
<div className="flex items-center space-x-2 mb-1">
<Switch
id="download-completion-notification"
checked={downloadCompletionNotification}
onCheckedChange={(checked) => saveSettingsKey('download_completion_notification', checked)}
disabled={!enableNotifications}
/>
<Label htmlFor="download-completion-notification">Download Completion</Label>
</div>
</div>
</div>
</TabsContent>
<TabsContent key="commands" value="commands" className="flex flex-col gap-4 min-h-[425px]">
<div className="custom-commands">
<h3 className="font-semibold">Custom Commands</h3>
<p className="text-xs text-muted-foreground mb-3"> Run custom yt-dlp commands for your downloads</p>
@@ -1238,7 +1309,7 @@ export default function SettingsPage() {
</div>
</div>
</TabsContent>
<TabsContent key="debug" value="debug" className="flex flex-col gap-4 min-h-[385px]">
<TabsContent key="debug" value="debug" className="flex flex-col gap-4 min-h-[425px]">
<div className="debug-mode">
<h3 className="font-semibold">Debug Mode</h3>
<p className="text-xs text-muted-foreground mb-3">Enable debug mode for troubleshooting issues (get debug logs, download ids, and more)</p>

View File

@@ -58,6 +58,7 @@ export const useDownloaderPageStatesStore = create<DownloaderPageStatesStore>((s
output_format: null,
embed_metadata: null,
embed_thumbnail: null,
sponsorblock: null,
custom_command: null
},
isErrored: false,
@@ -83,6 +84,7 @@ export const useDownloaderPageStatesStore = create<DownloaderPageStatesStore>((s
output_format: null,
embed_metadata: null,
embed_thumbnail: null,
sponsorblock: null,
custom_command: null
}
})),
@@ -163,6 +165,7 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
always_reencode_video: false,
embed_video_metadata: false,
embed_audio_metadata: true,
embed_video_thumbnail: false,
embed_audio_thumbnail: true,
use_cookies: false,
import_cookies_from: 'browser',
@@ -184,6 +187,9 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
log_verbose: true,
log_warning: true,
log_progress: false,
enable_notifications: false,
update_notification: true,
download_completion_notification: false,
// extension settings
websocket_port: 53511
},
@@ -228,6 +234,7 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
always_reencode_video: false,
embed_video_metadata: false,
embed_audio_metadata: true,
embed_video_thumbnail: false,
embed_audio_thumbnail: true,
use_cookies: false,
import_cookies_from: 'browser',
@@ -249,6 +256,9 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
log_verbose: true,
log_warning: true,
log_progress: false,
enable_notifications: false,
update_notification: true,
download_completion_notification: false,
// extension settings
websocket_port: 53511
},

View File

@@ -27,6 +27,7 @@ export interface Settings {
always_reencode_video: boolean;
embed_video_metadata: boolean;
embed_audio_metadata: boolean;
embed_video_thumbnail: boolean;
embed_audio_thumbnail: boolean;
use_cookies: boolean;
import_cookies_from: string;
@@ -48,6 +49,9 @@ export interface Settings {
log_verbose: boolean;
log_warning: boolean;
log_progress: boolean;
enable_notifications: boolean;
update_notification: boolean;
download_completion_notification: boolean;
// extension settings
websocket_port: number;
}
@@ -56,5 +60,6 @@ export interface DownloadConfiguration {
output_format: string | null;
embed_metadata: boolean | null;
embed_thumbnail: boolean | null;
sponsorblock: string | null;
custom_command: string | null;
}