Compare commits
27 Commits
2
.gitattributes
vendored
@@ -1,3 +1 @@
|
|||||||
* text=auto eol=lf
|
* text=auto eol=lf
|
||||||
|
|
||||||
src-tauri/binaries/* filter=lfs diff=lfs merge=lfs -text
|
|
||||||
40
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: "[BUG]"
|
||||||
|
labels: bug
|
||||||
|
assignees: neosubhamoy
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**OS info (required):**
|
||||||
|
- OS: [e.g. Windows 11]
|
||||||
|
- OS Architecture: [e.g. x64]
|
||||||
|
- OS Version: [e.g. 25H2 26200.6899]
|
||||||
|
|
||||||
|
**App info (required):**
|
||||||
|
- NeoDLP Version: [e.g. 0.3.1]
|
||||||
|
- YT-DLP Version: [e.g. 2025.10.18.232824]
|
||||||
|
- NeoDLP Installation Mode: [e.g. msi, exe, winget]
|
||||||
|
|
||||||
|
**App logs (required):**
|
||||||
|
Paste the full app session logs here
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: "[FEATURE REQUEST]"
|
||||||
|
labels: feature request
|
||||||
|
assignees: neosubhamoy
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
31
.github/ISSUE_TEMPLATE/test_result.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: Test result
|
||||||
|
about: Share your test results
|
||||||
|
title: "[TEST RESULT]"
|
||||||
|
labels: test result
|
||||||
|
assignees: neosubhamoy
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the result**
|
||||||
|
A clear and concise description of what's the final result of your testing.
|
||||||
|
|
||||||
|
**Did you noticed any problem?**
|
||||||
|
Mention if you noticed any problems or inconsistencies during the testing
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain the results.
|
||||||
|
|
||||||
|
**What's working (required):**
|
||||||
|
- [ ] Package installation
|
||||||
|
- [ ] Downloads
|
||||||
|
- [ ] Settings and configurations
|
||||||
|
- [ ] Browser integration
|
||||||
|
|
||||||
|
**Test environment (required):**
|
||||||
|
- OS: [e.g. Windows 11]
|
||||||
|
- OS Architecture: [e.g. x64]
|
||||||
|
- OS Version: [e.g. 25H2 26200.6899]
|
||||||
|
- NeoDLP Version: [e.g. 0.3.1]
|
||||||
|
- YT-DLP Version: [e.g. 2025.10.18.232824]
|
||||||
|
- NeoDLP Installation Mode: [e.g. msi, exe, winget]
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
BIN
.github/images/completed-downloads.png
vendored
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
.github/images/downloader.png
vendored
Normal file
|
After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 541 KiB After Width: | Height: | Size: 541 KiB |
BIN
.github/images/ongoing-downloads.png
vendored
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
.github/images/settings.png
vendored
Normal file
|
After Width: | Height: | Size: 94 KiB |
9
.github/workflows/release.yml
vendored
@@ -25,9 +25,7 @@ jobs:
|
|||||||
runs-on: ${{ matrix.platform }}
|
runs-on: ${{ matrix.platform }}
|
||||||
steps:
|
steps:
|
||||||
- name: 🚚 Checkout repository
|
- name: 🚚 Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
|
|
||||||
- name: 🛠️ Install dependencies
|
- name: 🛠️ Install dependencies
|
||||||
if: matrix.platform == 'ubuntu-22.04' || matrix.platform == 'ubuntu-22.04-arm'
|
if: matrix.platform == 'ubuntu-22.04' || matrix.platform == 'ubuntu-22.04-arm'
|
||||||
@@ -36,7 +34,7 @@ jobs:
|
|||||||
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
||||||
|
|
||||||
- name: 📦 Setup node
|
- name: 📦 Setup node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 'lts/*'
|
node-version: 'lts/*'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@@ -54,6 +52,9 @@ jobs:
|
|||||||
- name: 🛠️ Install frontend dependencies
|
- name: 🛠️ Install frontend dependencies
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|
||||||
|
- name: 📥 Download binaries
|
||||||
|
run: npm run download
|
||||||
|
|
||||||
- name: 📄 Read and Process CHANGELOG (Unix)
|
- name: 📄 Read and Process CHANGELOG (Unix)
|
||||||
if: matrix.platform != 'windows-latest'
|
if: matrix.platform != 'windows-latest'
|
||||||
id: changelog_unix
|
id: changelog_unix
|
||||||
|
|||||||
17
.gitignore
vendored
@@ -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
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
@@ -7,12 +18,6 @@ yarn-error.log*
|
|||||||
pnpm-debug.log*
|
pnpm-debug.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
|
|
||||||
node_modules
|
|
||||||
dist
|
|
||||||
dist-ssr
|
|
||||||
*.local
|
|
||||||
.github/workflows/.secrets
|
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
|
|||||||
44
CHANGELOG.md
@@ -1,25 +1,19 @@
|
|||||||
### ✨ Changelog
|
### ✨ Changelog
|
||||||
|
|
||||||
- Added per-download configuration tweaks in downloader
|
- Added desktop notification settings (download completion, app updates)
|
||||||
- Added cookies support
|
- Added per-download sponsorblock config
|
||||||
- Added sponsorblock support (mark/remove segments)
|
- Added thumbnail embeding option for video files
|
||||||
- Added custom yt-dlp command support
|
- Fixed yt-dlp failing to update on Windows MSI install
|
||||||
- Added aria2 support (macos users need to install aria2 via homebrew to use this feature)
|
- Fixed yt-dlp not resolving deno on macOS
|
||||||
- Added force ipv protocol option in settings
|
- Other minor fixes and improvements
|
||||||
- Added filename template option in settings
|
|
||||||
- Added real-time app session log viewer (monitor detailed yt-dlp logs)
|
|
||||||
- Improved download resume persistence (now more essential settings are preserved on resume)
|
|
||||||
- Added quick search button for completed downloads in library
|
|
||||||
- Fixed completed download sorting order (last completed on top)
|
|
||||||
- Ships with deno javascript runtime (as per new yt-dlp requirement)
|
|
||||||
- Added new linux arm64 builds (deb, rpm)
|
|
||||||
- Lots of other fixes and improvements
|
|
||||||
|
|
||||||
### 📝 Notes
|
### 📝 Notes
|
||||||
|
|
||||||
> **🔴 DANGER:** This update introduces few breaking changes! 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.
|
> [!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.
|
||||||
|
|
||||||
> **⚠️ WARNING:** Linux users make sure `yt-dlp`, `ffmpeg`, `ffprobe` and `deno` is not installed in your distro (otherwise you will get package installation conflict). Don't worry, You can still use yt-dlp cli as before (the only difference is that now it will be installed and auto-updated by neo-dlp, which You can also disable from neo-dlp Settings if you don't want to auto-update yt-dlp)
|
> [!WARNING]
|
||||||
|
> Linux users make sure `yt-dlp` and `deno` is not installed in your distro (otherwise you will get package installation conflict). Don't worry, You can still use yt-dlp cli as before (the only difference is that now it will be installed and auto-updated by neo-dlp, which You can also disable from neo-dlp Settings if you don't want to auto-update yt-dlp)
|
||||||
|
|
||||||
> This is an Un-Signed Build (Windows doesn't trust this Certificate so, it may flag this as malicious software, in that case, disable Windows SmartScreen and Defender, install it, and then re-enable them)
|
> This is an Un-Signed Build (Windows doesn't trust this Certificate so, it may flag this as malicious software, in that case, disable Windows SmartScreen and Defender, install it, and then re-enable them)
|
||||||
|
|
||||||
@@ -29,17 +23,23 @@
|
|||||||
|
|
||||||
| yt-dlp (updateable) | ffmpeg | ffprobe | aria2c | deno |
|
| yt-dlp (updateable) | ffmpeg | ffprobe | aria2c | deno |
|
||||||
| :---- | :---- | :---- | :---- | :---- |
|
| :---- | :---- | :---- | :---- | :---- |
|
||||||
| v2025.10.01.232815 (nightly) | v7.1.1 | v7.1.1 | v1.37.0 | v2.5.3|
|
| v2025.11.03.233024 (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)
|
||||||
|
|
||||||
|
> ‼️ MacOS builds (dmg, app) does not ships with `aria2c`, If you want to use [aria2](https://formulae.brew.sh/formula/aria2) install it via [homebrew](https://brew.sh)
|
||||||
|
|
||||||
### ⬇️ Download Section
|
### ⬇️ Download Section
|
||||||
|
|
||||||
| Arch\OS | Windows (msi) ⬆️ | Windows (exe) ⬆️ | Linux (deb) | Linux (rpm) | MacOS (dmg) ⬆️ | MacOS (app) ⬆️ |
|
| Arch\OS | 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.msi) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_x64-setup.exe) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_amd64.deb) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP-<version>-1.x86_64.rpm) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_x64.dmg) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_x64.app.tar.gz) |
|
| 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.exe) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_arm64.deb) | [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP-<version>-1.aarch64.rpm) | ⚠️ [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_<version>_aarch64.dmg) | ⚠️ [Download](https://github.com/neosubhamoy/neodlp/releases/download/<release_tag>/NeoDLP_aarch64.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) |
|
||||||
|
|
||||||
> ⬆️ icon indicates this packaging format supports in-built app-updater
|
> ⬆️ All packages 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)
|
> 🪟 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)
|
||||||
|
|
||||||
|
> 🚫 Linux AppImage builds are experimental and does not support neodlp's browser intergration features due to it's sandboxed nature. Also, don't run the AppImage with portable (.home, .config) folders, it will break things (it is highly recommended to use native [deb, rpm, AUR] builds if possible for the full experiance, otherwise AppImages are good for trying out NeoDLP without installing)
|
||||||
|
|
||||||
> ⚠️ MacOS ARM64 binary downloads are experimental and may not open on Apple Silicon Macs if downloaded from browser (You will get 'Damaged File' error) it's because the binaries are not signed (signing MacOS binaries requires 99$/year Apple Developer Account subscription, which I can't afford RN!) and Apple Silicon Macs don't allow unsigned apps (downloaded from browser) to be installed on the system. If you want to use NeoDLP on your Apple Silicon Macs, you can simply use the command line [Curl-Bash Installer](https://neodlp.neosubhamoy.com/download) (Recommended) -OR- [compile it from source](https://github.com/neosubhamoy/neodlp?tab=readme-ov-file#%EF%B8%8F-contributing--building-from-source) in your Mac
|
> ⚠️ MacOS ARM64 binary downloads are experimental and may not open on Apple Silicon Macs if downloaded from browser (You will get 'Damaged File' error) it's because the binaries are not signed (signing MacOS binaries requires 99$/year Apple Developer Account subscription, which I can't afford RN!) and Apple Silicon Macs don't allow unsigned apps (downloaded from browser) to be installed on the system. If you want to use NeoDLP on your Apple Silicon Macs, you can simply use the command line [Curl-Bash Installer](https://neodlp.neosubhamoy.com/download) (Recommended) -OR- [compile it from source](https://github.com/neosubhamoy/neodlp?tab=readme-ov-file#%EF%B8%8F-contributing--building-from-source) in your Mac
|
||||||
|
|||||||
89
README.md
@@ -1,4 +1,4 @@
|
|||||||

|

|
||||||
|
|
||||||
# NeoDLP - (Neo Downloader Plus)
|
# NeoDLP - (Neo Downloader Plus)
|
||||||
|
|
||||||
@@ -9,11 +9,12 @@ Cross-platform Video/Audio Downloader Desktop App with Modern UI and Browser Int
|
|||||||
[](https://github.com/neosubhamoy/neodlp/releases)
|
[](https://github.com/neosubhamoy/neodlp/releases)
|
||||||
[](https://github.com/neosubhamoy/neodlp)
|
[](https://github.com/neosubhamoy/neodlp)
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
> **🥰 Liked this project? Please consider giving it a Star (🌟) on github to show us your appreciation and help the algorythm recommend this project to even more awesome people like you!**
|
> **🥰 Liked this project? Please consider giving it a Star (🌟) on github to show us your appreciation and help the algorythm recommend this project to even more awesome people like you!**
|
||||||
|
|
||||||
[](https://repology.org/project/neodlp/versions)
|
[](https://repology.org/project/neodlp/versions)
|
||||||
|
|
||||||
### ✨ Highlighted Features
|
## ✨ Highlighted Features
|
||||||
|
|
||||||
- Download Video/Audio from popular sites (YT, FB, IG, X and other 2.5k+ [supported sites](https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md))
|
- Download Video/Audio from popular sites (YT, FB, IG, X and other 2.5k+ [supported sites](https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md))
|
||||||
- Download Video/Audio in your preffered format (MP4, WEBM, MKV, MP3 etc.)
|
- Download Video/Audio in your preffered format (MP4, WEBM, MKV, MP3 etc.)
|
||||||
@@ -25,7 +26,7 @@ Cross-platform Video/Audio Downloader Desktop App with Modern UI and Browser Int
|
|||||||
- Network controls (proxy, rate limit etc.)
|
- Network controls (proxy, rate limit etc.)
|
||||||
- Highly customizable and many more...😉
|
- Highly customizable and many more...😉
|
||||||
|
|
||||||
### 🧩 Browser Integration
|
## 🧩 Browser Integration
|
||||||
|
|
||||||
You can integrate NeoDLP with your favourite browser (any Chrome/Chromium/Firefox based browser) Just, install [NeoDLP Extension](https://github.com/neosubhamoy/neodlp-extension) to get started!
|
You can integrate NeoDLP with your favourite browser (any Chrome/Chromium/Firefox based browser) Just, install [NeoDLP Extension](https://github.com/neosubhamoy/neodlp-extension) to get started!
|
||||||
|
|
||||||
@@ -35,26 +36,34 @@ After installing the extension you can do the following directly from the browse
|
|||||||
|
|
||||||
- Right Click Context Menu Action (Download with Neo Downloader Plus - Link, Selection, Media Source)
|
- Right Click Context Menu Action (Download with Neo Downloader Plus - Link, Selection, Media Source)
|
||||||
|
|
||||||
### 👀 Sneak Peek
|
## 👀 Sneak Peek
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### 💻 Supported Platforms
|
| Downloader | Completed Downloads | Ongoing Downloads | Settings |
|
||||||
|
| :---- | :---- | :---- | :---- |
|
||||||
|
|  |  |  |  |
|
||||||
|
|
||||||
|
## 💻 Supported Platforms
|
||||||
|
|
||||||
- Windows (10 / 11)
|
- Windows (10 / 11)
|
||||||
- Linux (Debian / Fedora / Arch Linux base)
|
- Linux (Debian / Fedora / RHEL / SUSE / Arch Linux base)
|
||||||
- MacOS (>11)
|
- MacOS (>11)
|
||||||
|
|
||||||
> ⚠️ **NOTE:** Though most linux (debian/fedora/arch base) distros are supported but not all packages are tested on all these platforms, to save some time (and brain cells) and ship the software as fast as possible! (Currently only the debian package is tested on Ubuntu 24.04 LTS - So, other linux packages may have issues, test it yourself and feel free to report issues if you found one)
|
## 🤝 External Dependencies
|
||||||
|
|
||||||
### 🤝 External Dependencies
|
|
||||||
|
|
||||||
- [YT-DLP](https://github.com/yt-dlp/yt-dlp) - The core CLI tool used to download video/audio from the web (Hero of the show 😎)
|
- [YT-DLP](https://github.com/yt-dlp/yt-dlp) - The core CLI tool used to download video/audio from the web (Hero of the show 😎)
|
||||||
- [FFmpeg & FFprobe](https://www.ffmpeg.org) - Used for video/audio post-processing
|
- [FFmpeg & FFprobe](https://www.ffmpeg.org) - Used for video/audio post-processing
|
||||||
- [Aria2](https://aria2.github.io) - Used as an external downloader for blazing fast downloads with yt-dlp (Not included with NeoDLP MacOS builds)
|
- [Aria2](https://aria2.github.io) - Used as an external downloader for blazing fast downloads with yt-dlp (Not included with NeoDLP MacOS builds)
|
||||||
- [Deno](https://deno.com) - Provides sandboxed javascript runtime environment for yt-dlp (Required for YT downloads, as per the new yt-dlp [announcement](https://github.com/yt-dlp/yt-dlp/issues/14404))
|
- [Deno](https://deno.com) - Provides sandboxed javascript runtime environment for yt-dlp (Required for YT downloads, as per the new yt-dlp [announcement](https://github.com/yt-dlp/yt-dlp/issues/14404))
|
||||||
|
|
||||||
### ⬇️ Download and Installation
|
## ℹ️ System Pre-Requirements
|
||||||
|
|
||||||
|
- **Windows:** [Microsoft Visual C++ Redistributable 2015+](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170) `winget install Microsoft.VCRedist.2015+.x64` (Will be auto-installed if you install NeoDLP via winget)
|
||||||
|
- **MacOS:** XCode Command Line Tools `xcode-select --install` (Mostly, comes pre-installed on modern macos, still if you encounter any issue then try installing it manually)
|
||||||
|
- **Linux:** Most linux packages comes with pre-defined system dependencies which will be auto installed 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. also, if you prefer to install dependencies manually [follow this](https://v2.tauri.app/start/prerequisites/#linux))
|
||||||
|
|
||||||
|
## ⬇️ Download and Installation
|
||||||
|
|
||||||
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)
|
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)
|
||||||
|
|
||||||
@@ -63,15 +72,37 @@ After installing the extension you can do the following directly from the browse
|
|||||||
| 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) |
|
| 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) |
|
| ARM64 | ✅ Emulation | ✅ [Download](https://github.com/neosubhamoy/neodlp/releases/latest) | ✅ [Download](https://github.com/neosubhamoy/neodlp/releases/latest) |
|
||||||
|
|
||||||
> 📌 **NOTE:** x86_64 Windows 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)
|
> [!NOTE]
|
||||||
|
> x86_64 Windows 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)
|
||||||
|
|
||||||
| Platform (OS) | Distribution Channel | Installation Command / Instruction |
|
| Platform (OS) | Distribution Channel | Installation Command / Instruction |
|
||||||
| :---- | :---- | :---- |
|
| :---- | :---- | :---- |
|
||||||
| Windows x86_64 / ARM64 | WinGet | `winget install neodlp` |
|
| Windows x86_64 / ARM64 | WinGet | `winget install neodlp` |
|
||||||
| MacOS x86_64 / ARM64 | Curl-Bash Installer | `curl -sSL https://neodlp.neosubhamoy.com/neodlp_macos_installer.sh \| bash` |
|
| MacOS x86_64 / ARM64 | Curl-Bash Installer | `curl -sSL https://neodlp.neosubhamoy.com/macos_installer.sh \| bash` |
|
||||||
| Linux x86_64 (Arch Linux) | AUR | `yay -S neodlp` |
|
| Linux x86_64 / ARM64 | Curl-Bash Installer | `curl -sSL https://neodlp.neosubhamoy.com/linux_installer.sh \| bash` |
|
||||||
|
| Arch Linux x86_64 / ARM64 | AUR | `yay -S neodlp` |
|
||||||
|
|
||||||
### 💝 Support the Development
|
## 🧪 Package Testing Status
|
||||||
|
|
||||||
|
Though NeoDLP is supported on most platforms but not all packages are tested on all platforms, to save some time (and brain cells) and ship the software as fast as possible! Current test coverage is given below. So, untested packages may have issues, test it yourself and always feel free to report any issue on github.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> If you have access to any of the untested systems listed below, you can test the packages there and send me the test results via creating an github issue! (that would be super helpful actualy 😊)
|
||||||
|
|
||||||
|
| Platform | Status | Platform | Status |
|
||||||
|
| :---- | :---- | :---- | :---- |
|
||||||
|
| Windows 10 (x64) | ✅ Tested | Windows 10 (ARM64) | ⚠️ Untested |
|
||||||
|
| Windows 11 (x64) | ✅ Tested | Windows 11 (ARM64) | ✅ Tested |
|
||||||
|
| MacOS 14 (x64) | ✅ Tested | MacOS 14 (ARM64) | ✅ Tested |
|
||||||
|
| MacOS 15 (x64) | ⚠️ Untested | MacOS 15 (ARM64) | ✅ Tested |
|
||||||
|
| MacOS 26 (x64) | ⚠️ Untested | MacOS 26 (ARM64) | ✅ Tested |
|
||||||
|
| Ubuntu 24.04 LTS (x64) | ✅ Tested | Ubuntu 24.04 LTS (ARM64) | ⚠️ Untested |
|
||||||
|
| Fedora 42 (x64) | ✅ Tested | Fedora 42 (ARM64) | ⚠️ Untested |
|
||||||
|
| Arch Linux (x64) | ✅ Tested | Arch Linux (ARM64) | ✅ Tested |
|
||||||
|
| openSUSE 16 (x64) | ⚠️ Untested | openSUSE 16 (ARM64) | ⚠️ Untested |
|
||||||
|
| RHEL 10 (x64) | ⚠️ Untested | RHEL 10 (ARM64) | ⚠️ Untested |
|
||||||
|
|
||||||
|
## 💝 Support the Development
|
||||||
|
|
||||||
NeoDLP is and will be always FREE to Use and Open-Sourced for Everyone. On the other hand the developent process of NeoDLP takes lots of time, effort and even sometimes money! So, if you appriciate my work and have the ability to donate, then please consider supporting the development by donating (even a very small donation matters and helps NeoDLP to be a better product!) Your support is the key to my motivation...🤗
|
NeoDLP is and will be always FREE to Use and Open-Sourced for Everyone. On the other hand the developent process of NeoDLP takes lots of time, effort and even sometimes money! So, if you appriciate my work and have the ability to donate, then please consider supporting the development by donating (even a very small donation matters and helps NeoDLP to be a better product!) Your support is the key to my motivation...🤗
|
||||||
|
|
||||||
@@ -80,21 +111,23 @@ NeoDLP is and will be always FREE to Use and Open-Sourced for Everyone. On the o
|
|||||||
</a>
|
</a>
|
||||||
<br></br>
|
<br></br>
|
||||||
|
|
||||||
> 📌 **NOTE:** You can also donate via UPI by sending donations to this UPI ID directly: **subhamoybiswas636-2@oksbi**
|
> [!NOTE]
|
||||||
|
> You can also donate via UPI by sending donations to this UPI ID directly: **subhamoybiswas636-2@oksbi**
|
||||||
|
|
||||||
### 🪜 Roadmap
|
## 🪜 Roadmap
|
||||||
|
|
||||||
- [x] Add support for yt-dlp
|
- [x] Add support for yt-dlp
|
||||||
- [x] Add basic settings and customization
|
- [x] Add basic settings and customization
|
||||||
- [x] Integrate with browsers
|
- [x] Integrate with browsers
|
||||||
- [x] Add aria2c support
|
- [x] Add aria2c support
|
||||||
|
- [x] Add custom command support
|
||||||
- [ ] Add more advanced settings and achive stability **(ongoing)**
|
- [ ] Add more advanced settings and achive stability **(ongoing)**
|
||||||
- [ ] Add media converter
|
- [ ] Add media converter
|
||||||
- [ ] Add multiple downloader engines
|
- [ ] Add multiple downloader engines
|
||||||
- [ ] Add advanced web extractor
|
- [ ] Add advanced web extractor
|
||||||
- [ ] Add more cool stuffs 😉
|
- [ ] Add more cool stuffs 😉
|
||||||
|
|
||||||
### ⚡ Technologies Used
|
## ⚡ Technologies Used
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
@@ -102,24 +135,26 @@ NeoDLP is and will be always FREE to Use and Open-Sourced for Everyone. On the o
|
|||||||

|

|
||||||

|

|
||||||
|
|
||||||
### 🛠️ Contributing / Building from Source
|
## 🛠️ Contributing / Building from Source
|
||||||
|
|
||||||
Want to be part of this? Feel free to contribute...!! Pull Requests are always welcome...!! (^_^) Follow these simple steps to start building:
|
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
|
* Install [Tauri Prerequisites](https://v2.tauri.app/start/prerequisites/) for your OS / platform
|
||||||
1. Fork this repo in your github account.
|
1. Fork this repo in your github account.
|
||||||
2. Git clone the forked repo in your local machine.
|
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)
|
3. Create a git branch (related to the feature you are working on) (Optional - Recommended)
|
||||||
4. Install Node.js dependencies: `npm install`
|
4. Install Node.js dependencies: `npm install`
|
||||||
5. Run development / build process
|
5. Download binaries (for current platform): `npm run download`
|
||||||
> ⚠️ **IMPORTANT:** Make sure to run the build command once before running the dev command for the first time to avoid compile time errors
|
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
|
```code
|
||||||
# for windows users
|
# for windows users
|
||||||
npm run tauri dev # for development
|
npm run tauri dev # for development
|
||||||
npm run tauri build # for production build
|
npm run tauri build # for production build
|
||||||
|
|
||||||
# for linux users
|
# for linux users (based on cpu architecture)
|
||||||
npm run tauri dev -- --config "./src-tauri/tauri.linux-aarch64.conf.json" # for ARM64 devices, development
|
npm run tauri dev -- --config "./src-tauri/tauri.linux-aarch64.conf.json" # for ARM64 devices, development
|
||||||
npm run tauri build -- --config "./src-tauri/tauri.linux-aarch64.conf.json" # for ARM64 devices, production build
|
npm run tauri build -- --config "./src-tauri/tauri.linux-aarch64.conf.json" # for ARM64 devices, production build
|
||||||
|
|
||||||
@@ -135,16 +170,16 @@ npm run tauri build -- --config "./src-tauri/tauri.macos-x86_64.conf.json" #
|
|||||||
```
|
```
|
||||||
6. Do the changes, Send a Pull Request with proper Description (NOTE: Pull Requests Without Proper Description will be Rejected)
|
6. Do the changes, Send a Pull Request with proper Description (NOTE: Pull Requests Without Proper Description will be Rejected)
|
||||||
|
|
||||||
### ⭕ Bug Report
|
## ⭕ Bug Report
|
||||||
|
|
||||||
Noticed any Bug? or Want to give me some suggetion? Always feel free to open a [GitHub Issue](https://github.com/neosubhamoy/neodlp/issues). I would love to hear from you...!!
|
Noticed any Bug? or Want to give me some suggetion? Always feel free to open a [GitHub Issue](https://github.com/neosubhamoy/neodlp/issues). I would love to hear from you...!!
|
||||||
|
|
||||||
### 💫 Credits
|
## 💫 Credits
|
||||||
|
|
||||||
- NeoDLP's 'Format Selection' options are inspired from the [Seal](https://github.com/JunkFood02/Seal) app by [@JunkFood02](https://github.com/JunkFood02)
|
- 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
|
## 📝 License
|
||||||
|
|
||||||
NeoDLP is Licensed under the [MIT license](https://github.com/neosubhamoy/neodlp/blob/main/LICENSE). Anyone can view, modify, use (personal and commercial) or distribute it's sources without any attribution and extra permissions.
|
NeoDLP is Licensed under the [MIT license](https://github.com/neosubhamoy/neodlp/blob/main/LICENSE). Anyone can view, modify, use (personal and commercial) or distribute it's sources without any attribution and extra permissions.
|
||||||
|
|
||||||
|
|||||||
1013
package-lock.json
generated
63
package.json
@@ -1,53 +1,56 @@
|
|||||||
{
|
{
|
||||||
"name": "neodlp",
|
"name": "neodlp",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.3.0",
|
"version": "0.3.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"tauri": "tauri"
|
"tauri": "tauri",
|
||||||
|
"download": "node ./scripts/download-bins.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^5.2.2",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
"@radix-ui/react-accordion": "^1.2.12",
|
"@radix-ui/react-accordion": "^1.2.12",
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
"@radix-ui/react-aspect-ratio": "^1.1.8",
|
||||||
"@radix-ui/react-avatar": "^1.1.10",
|
"@radix-ui/react-avatar": "^1.1.11",
|
||||||
"@radix-ui/react-checkbox": "^1.3.3",
|
"@radix-ui/react-checkbox": "^1.3.3",
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
"@radix-ui/react-context-menu": "^2.2.16",
|
"@radix-ui/react-context-menu": "^2.2.16",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
"@radix-ui/react-hover-card": "^1.1.15",
|
"@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-menubar": "^1.1.16",
|
||||||
"@radix-ui/react-navigation-menu": "^1.2.14",
|
"@radix-ui/react-navigation-menu": "^1.2.14",
|
||||||
"@radix-ui/react-popover": "^1.1.15",
|
"@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-radio-group": "^1.3.8",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
"@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-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-switch": "^1.2.6",
|
||||||
"@radix-ui/react-tabs": "^1.1.13",
|
"@radix-ui/react-tabs": "^1.1.13",
|
||||||
"@radix-ui/react-toast": "^1.2.15",
|
"@radix-ui/react-toast": "^1.2.15",
|
||||||
"@radix-ui/react-toggle": "^1.1.10",
|
"@radix-ui/react-toggle": "^1.1.10",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.11",
|
"@radix-ui/react-toggle-group": "^1.1.11",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"@tanstack/react-query": "^5.90.2",
|
"@tanstack/react-query": "^5.90.7",
|
||||||
"@tanstack/react-query-devtools": "^5.90.2",
|
"@tanstack/react-query-devtools": "^5.90.2",
|
||||||
"@tauri-apps/api": "^2.8.0",
|
"@tauri-apps/api": "^2.9.0",
|
||||||
"@tauri-apps/plugin-dialog": "^2.4.0",
|
"@tauri-apps/plugin-clipboard-manager": "^2.3.2",
|
||||||
"@tauri-apps/plugin-fs": "^2.4.2",
|
"@tauri-apps/plugin-dialog": "^2.4.2",
|
||||||
"@tauri-apps/plugin-opener": "^2.5.0",
|
"@tauri-apps/plugin-fs": "^2.4.4",
|
||||||
"@tauri-apps/plugin-os": "^2.3.1",
|
"@tauri-apps/plugin-notification": "^2.3.3",
|
||||||
"@tauri-apps/plugin-process": "^2.3.0",
|
"@tauri-apps/plugin-opener": "^2.5.2",
|
||||||
"@tauri-apps/plugin-shell": "^2.3.1",
|
"@tauri-apps/plugin-os": "^2.3.2",
|
||||||
"@tauri-apps/plugin-sql": "^2.3.0",
|
"@tauri-apps/plugin-process": "^2.3.1",
|
||||||
|
"@tauri-apps/plugin-shell": "^2.3.3",
|
||||||
|
"@tauri-apps/plugin-sql": "^2.3.1",
|
||||||
"@tauri-apps/plugin-updater": "^2.9.0",
|
"@tauri-apps/plugin-updater": "^2.9.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
@@ -55,15 +58,15 @@
|
|||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"embla-carousel-react": "^8.6.0",
|
"embla-carousel-react": "^8.6.0",
|
||||||
"input-otp": "^1.4.2",
|
"input-otp": "^1.4.2",
|
||||||
"lucide-react": "^0.545.0",
|
"lucide-react": "^0.552.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "^19.2.0",
|
"react": "^19.2.0",
|
||||||
"react-day-picker": "^9.11.0",
|
"react-day-picker": "^9.11.1",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "^19.2.0",
|
||||||
"react-hook-form": "^7.64.0",
|
"react-hook-form": "^7.66.0",
|
||||||
"react-resizable-panels": "^3.0.6",
|
"react-resizable-panels": "^3.0.6",
|
||||||
"react-router-dom": "^7.9.3",
|
"react-router-dom": "^7.9.5",
|
||||||
"recharts": "^3.2.1",
|
"recharts": "^3.3.0",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.3.1",
|
"tailwind-merge": "^3.3.1",
|
||||||
"ulid": "^3.0.1",
|
"ulid": "^3.0.1",
|
||||||
@@ -72,17 +75,17 @@
|
|||||||
"zustand": "^5.0.8"
|
"zustand": "^5.0.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.14",
|
"@tailwindcss/postcss": "^4.1.16",
|
||||||
"@tailwindcss/vite": "^4.1.14",
|
"@tailwindcss/vite": "^4.1.16",
|
||||||
"@tauri-apps/cli": "^2.8.4",
|
"@tauri-apps/cli": "^2.9.3",
|
||||||
"@types/node": "^24.7.0",
|
"@types/node": "^24.10.0",
|
||||||
"@types/react": "^19.2.2",
|
"@types/react": "^19.2.2",
|
||||||
"@types/react-dom": "^19.2.1",
|
"@types/react-dom": "^19.2.2",
|
||||||
"@vitejs/plugin-react": "^5.0.4",
|
"@vitejs/plugin-react": "^5.1.0",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"tailwindcss": "^4.1.14",
|
"tailwindcss": "^4.1.16",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"vite": "^7.1.9"
|
"vite": "^7.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import { execSync } from 'child_process';
|
|||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
|
const projectRoot = path.resolve(__dirname, '..');
|
||||||
|
|
||||||
// Define array of binary source directories
|
// Define array of binary source directories
|
||||||
const binSrcDirs = [
|
const binSrcDirs = [
|
||||||
path.join(__dirname, 'src-tauri', 'binaries'),
|
path.join(projectRoot, 'src-tauri', 'binaries'),
|
||||||
];
|
];
|
||||||
|
|
||||||
function makeFilesExecutable() {
|
function makeFilesExecutable() {
|
||||||
@@ -46,5 +47,5 @@ function makeFilesExecutable() {
|
|||||||
console.log(`\nSummary: Made ${totalCount} files executable across ${successDirs} directories`);
|
console.log(`\nSummary: Made ${totalCount} files executable across ${successDirs} directories`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`RUNNING: 🛠️ Build Script makeFilesExecutable.js`);
|
console.log(`RUNNING: 🛠️ Build Script --> chmod.js`);
|
||||||
makeFilesExecutable();
|
makeFilesExecutable();
|
||||||
442
scripts/download-bins.js
Normal 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');
|
||||||
@@ -5,8 +5,9 @@ import { fileURLToPath } from 'url';
|
|||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
|
const projectRoot = path.resolve(__dirname, '..');
|
||||||
|
|
||||||
console.log(`RUNNING: 🛠️ Build Script updateYtDlpBinary.js`);
|
console.log(`RUNNING: 🛠️ Build Script --> update-yt-dlp.js`);
|
||||||
|
|
||||||
// Get the platform triple from command line arguments
|
// Get the platform triple from command line arguments
|
||||||
const platformTriple = process.argv[2];
|
const platformTriple = process.argv[2];
|
||||||
@@ -17,7 +18,7 @@ if (!platformTriple) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Define the binaries directory
|
// Define the binaries directory
|
||||||
const binariesDir = path.join(__dirname, 'src-tauri', 'binaries');
|
const binariesDir = path.join(projectRoot, 'src-tauri', 'binaries');
|
||||||
|
|
||||||
// Construct the binary filename based on platform triple
|
// Construct the binary filename based on platform triple
|
||||||
let binaryName = `yt-dlp-${platformTriple}`;
|
let binaryName = `yt-dlp-${platformTriple}`;
|
||||||
1136
src-tauri/Cargo.lock
generated
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "neodlp"
|
name = "neodlp"
|
||||||
version = "0.3.0"
|
version = "0.3.3"
|
||||||
description = "NeoDLP"
|
description = "NeoDLP"
|
||||||
authors = ["neosubhamoy <hey@neosubhamoy.com>"]
|
authors = ["neosubhamoy <hey@neosubhamoy.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -29,6 +29,7 @@ sqlx = { version = "0.8", features = [ "sqlite", "runtime-tokio", "tls-native-tl
|
|||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
directories = "6.0"
|
directories = "6.0"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
|
fix-path-env = { git = "https://github.com/tauri-apps/fix-path-env-rs" }
|
||||||
tauri-plugin-opener = "2"
|
tauri-plugin-opener = "2"
|
||||||
tauri-plugin-shell = "2"
|
tauri-plugin-shell = "2"
|
||||||
tauri-plugin-fs = "2"
|
tauri-plugin-fs = "2"
|
||||||
@@ -36,6 +37,8 @@ tauri-plugin-os = "2"
|
|||||||
tauri-plugin-dialog = "2"
|
tauri-plugin-dialog = "2"
|
||||||
tauri-plugin-sql = { version = "2", features = ["sqlite"] }
|
tauri-plugin-sql = { version = "2", features = ["sqlite"] }
|
||||||
tauri-plugin-process = "2"
|
tauri-plugin-process = "2"
|
||||||
|
tauri-plugin-clipboard-manager = "2"
|
||||||
|
tauri-plugin-notification = "2"
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||||
tauri-plugin-single-instance = "2"
|
tauri-plugin-single-instance = "2"
|
||||||
|
|||||||
0
src-tauri/binaries/.gitkeep
Normal file
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:9397aac0de54c8c15b8166486eb80bfe27937bd6d6b6af4bb8383b155213bec1
|
|
||||||
size 6100888
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:cca868da48a85c13a56ccac4dfa8c098f7ed799786a9eaf88248221dbb785bb9
|
|
||||||
size 8089088
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:36f66dab69edcc44255d0dba90c93f5aa4a304ec60c7136d8c279dfc89c23e1d
|
|
||||||
size 9666624
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:1037b241d626483d0048c5ef459aa9fa13cd6bc2bc57d2c7a2aaf7e3b7515f78
|
|
||||||
size 91614816
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:0716e9b52129cb0e43aa33064f641788650a2162681780590ec67dbca419d74f
|
|
||||||
size 103264328
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:510c9d6ded38568a13dfb0acdaa178f060ee5cacb37aeb9ae500724e460a8e79
|
|
||||||
size 102745408
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:522e54fc5ca4cb42bc9bb7ed952327481c8b6d20149a8d8e7f7b7a604f9ed199
|
|
||||||
size 117758936
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:df96c25d1804cee25e463d5084a7ded48b6d9d58f8b0d819644a960aa13a7230
|
|
||||||
size 113525240
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:81eb29b0678f4749cc01934b954f57cdd858c9afce5adf6872394adb5ffb2be2
|
|
||||||
size 80268888
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:9e085bde1b47b05d41b23d3f60526067894ba92ce7eba1668c38d460a37c9bb2
|
|
||||||
size 137315712
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:81eb29b0678f4749cc01934b954f57cdd858c9afce5adf6872394adb5ffb2be2
|
|
||||||
size 80268888
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:7d3403afa6d8510aca69d4b3c99619d972fb4651e4787c2de019f1404a139019
|
|
||||||
size 175262208
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:1058b4d448ddcdd2a7e560f928f0c18197c6f8b8cc25a489a95c5e1989b82d88
|
|
||||||
size 176215272
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:2559a63f05e35f2d2d771a2044c1463d6be1e7f0279e67869d5d9bc658556894
|
|
||||||
size 80086968
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:b22c9ad49225bf133ccbb9e2a6494ba2b8c83f4c0514b24e06bdb2c6d6fa7427
|
|
||||||
size 137124736
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:2559a63f05e35f2d2d771a2044c1463d6be1e7f0279e67869d5d9bc658556894
|
|
||||||
size 80086968
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:b49251407a2e2e1a9d00722a89a4163a1f89e128108155585f4ef6c79bcfbd85
|
|
||||||
size 175064064
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:cbdef955953b157ee366c162746ccafdb4e2bc1a154e8d6d97bf57751b7e6918
|
|
||||||
size 176011752
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:c5d493c97561527824d64327b60221bc2646747c30953423e818715f3cea5c3a
|
|
||||||
size 35709136
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:45213ee9e85de7ecc4ea4edd4862dbf8cd8899d109c469500b1434ac47f80474
|
|
||||||
size 37262312
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:c5d493c97561527824d64327b60221bc2646747c30953423e818715f3cea5c3a
|
|
||||||
size 35709136
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:619d7fa15ff4cdafbf912530799acf32bb4227b363bc8144cb377d82a9ecb6ac
|
|
||||||
size 18332203
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:ab4161f2fa57092a8d5f4448ed5aef1c814aa38cddc37d068aaf91b0a517c2ea
|
|
||||||
size 37574216
|
|
||||||
@@ -22,6 +22,9 @@
|
|||||||
"fs:allow-app-write-recursive",
|
"fs:allow-app-write-recursive",
|
||||||
"updater:default",
|
"updater:default",
|
||||||
"process:default",
|
"process:default",
|
||||||
|
"clipboard-manager:allow-read-text",
|
||||||
|
"clipboard-manager:allow-write-text",
|
||||||
|
"notification:default",
|
||||||
{
|
{
|
||||||
"identifier": "opener:allow-open-path",
|
"identifier": "opener:allow-open-path",
|
||||||
"allow": [
|
"allow": [
|
||||||
|
|||||||
@@ -35,6 +35,11 @@
|
|||||||
"args": true,
|
"args": true,
|
||||||
"sidecar": true
|
"sidecar": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ffmpeg",
|
||||||
|
"cmd": "ffmpeg",
|
||||||
|
"args": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "aria2c",
|
"name": "aria2c",
|
||||||
"cmd": "aria2c",
|
"cmd": "aria2c",
|
||||||
@@ -44,6 +49,11 @@
|
|||||||
"name": "pkexec",
|
"name": "pkexec",
|
||||||
"cmd": "pkexec",
|
"cmd": "pkexec",
|
||||||
"args": true
|
"args": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "powershell",
|
||||||
|
"cmd": "powershell",
|
||||||
|
"args": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -75,6 +85,11 @@
|
|||||||
"args": true,
|
"args": true,
|
||||||
"sidecar": true
|
"sidecar": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ffmpeg",
|
||||||
|
"cmd": "ffmpeg",
|
||||||
|
"args": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "aria2c",
|
"name": "aria2c",
|
||||||
"cmd": "aria2c",
|
"cmd": "aria2c",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
!macro NSIS_HOOK_POSTINSTALL
|
!macro NSIS_HOOK_POSTINSTALL
|
||||||
; Add Registry Keys for Chrome Native Messaging Host
|
; Add Registry Keys for Chrome Native Messaging Host
|
||||||
WriteRegStr HKCU "Software\Google\Chrome\NativeMessagingHosts\com.neosubhamoy.neodlp" "" "$INSTDIR\neodlp-msghost.json"
|
WriteRegStr HKCU "Software\Google\Chrome\NativeMessagingHosts\com.neosubhamoy.neodlp" "" "$INSTDIR\chrome.json"
|
||||||
; Add Registry Keys for Firefox Native Messaging Host
|
; Add Registry Keys for Firefox Native Messaging Host
|
||||||
WriteRegStr HKCU "Software\Mozilla\NativeMessagingHosts\com.neosubhamoy.neodlp" "" "$INSTDIR\neodlp-msghost-moz.json"
|
WriteRegStr HKCU "Software\Mozilla\NativeMessagingHosts\com.neosubhamoy.neodlp" "" "$INSTDIR\firefox.json"
|
||||||
; Add entry for automatic startup with Windows
|
; Add entry for automatic startup with Windows
|
||||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${PRODUCTNAME}" "$\"$INSTDIR\neodlp.exe$\" --hidden"
|
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${PRODUCTNAME}" "$\"$INSTDIR\neodlp.exe$\" --hidden"
|
||||||
!macroend
|
!macroend
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<DirectoryRef Id="TARGETDIR">
|
<DirectoryRef Id="TARGETDIR">
|
||||||
<Component Id="NeoDlpRegEntriesFragment" Guid="*">
|
<Component Id="NeoDlpRegEntriesFragment" Guid="*">
|
||||||
<RegistryKey Root="HKLM" Key="Software\Google\Chrome\NativeMessagingHosts\com.neosubhamoy.neodlp" Action="createAndRemoveOnUninstall">
|
<RegistryKey Root="HKLM" Key="Software\Google\Chrome\NativeMessagingHosts\com.neosubhamoy.neodlp" Action="createAndRemoveOnUninstall">
|
||||||
<RegistryValue Type="string" Value="[INSTALLDIR]neodlp-msghost.json" KeyPath="no" />
|
<RegistryValue Type="string" Value="[INSTALLDIR]chrome.json" KeyPath="no" />
|
||||||
</RegistryKey>
|
</RegistryKey>
|
||||||
<RegistryKey Root="HKLM" Key="Software\Mozilla\NativeMessagingHosts\com.neosubhamoy.neodlp" Action="createAndRemoveOnUninstall">
|
<RegistryKey Root="HKLM" Key="Software\Mozilla\NativeMessagingHosts\com.neosubhamoy.neodlp" Action="createAndRemoveOnUninstall">
|
||||||
<RegistryValue Type="string" Value="[INSTALLDIR]neodlp-msghost-moz.json" KeyPath="no" />
|
<RegistryValue Type="string" Value="[INSTALLDIR]firefox.json" KeyPath="no" />
|
||||||
</RegistryKey>
|
</RegistryKey>
|
||||||
<RegistryKey Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Run">
|
<RegistryKey Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Run">
|
||||||
<RegistryValue Name="NeoDLP" Type="string" Value=""[INSTALLDIR]neodlp.exe" --hidden" KeyPath="no" />
|
<RegistryValue Name="NeoDLP" Type="string" Value=""[INSTALLDIR]neodlp.exe" --hidden" KeyPath="no" />
|
||||||
|
|||||||
0
src-tauri/resources/downloads/.gitkeep
Normal 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]
|
#[tauri::command]
|
||||||
async fn update_config(
|
async fn update_config(
|
||||||
new_config: Config,
|
new_config: Config,
|
||||||
@@ -452,6 +462,7 @@ async fn pause_ongoing_downloads(
|
|||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub async fn run() {
|
pub async fn run() {
|
||||||
|
let _ = fix_path_env::fix();
|
||||||
let migrations = migrations::get_migrations();
|
let migrations = migrations::get_migrations();
|
||||||
let config = load_config();
|
let config = load_config();
|
||||||
let port = config.port;
|
let port = config.port;
|
||||||
@@ -485,6 +496,8 @@ pub async fn run() {
|
|||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
.plugin(tauri_plugin_process::init())
|
.plugin(tauri_plugin_process::init())
|
||||||
|
.plugin(tauri_plugin_clipboard_manager::init())
|
||||||
|
.plugin(tauri_plugin_notification::init())
|
||||||
.manage(ImageCache(StdMutex::new(HashMap::new())))
|
.manage(ImageCache(StdMutex::new(HashMap::new())))
|
||||||
.manage(websocket_state.clone())
|
.manage(websocket_state.clone())
|
||||||
.setup(move |app| {
|
.setup(move |app| {
|
||||||
@@ -586,6 +599,7 @@ pub async fn run() {
|
|||||||
reset_config,
|
reset_config,
|
||||||
get_config_file_path,
|
get_config_file_path,
|
||||||
restart_websocket_server,
|
restart_websocket_server,
|
||||||
|
get_current_app_path,
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "NeoDLP",
|
"productName": "NeoDLP",
|
||||||
"mainBinaryName": "neodlp",
|
"mainBinaryName": "neodlp",
|
||||||
"version": "0.3.0",
|
"version": "0.3.3",
|
||||||
"identifier": "com.neosubhamoy.neodlp",
|
"identifier": "com.neosubhamoy.neodlp",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "npm run dev",
|
"beforeDevCommand": "npm run dev",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"identifier": "com.neosubhamoy.neodlp",
|
"identifier": "com.neosubhamoy.neodlp",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "cargo build --target=aarch64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && node makeFilesExecutable.js && npm run dev",
|
"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 && node makeFilesExecutable.js && npm run build",
|
"beforeBuildCommand": "cargo build --release --target=aarch64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && npm run build",
|
||||||
"devUrl": "http://localhost:1420",
|
"devUrl": "http://localhost:1420",
|
||||||
"frontendDist": "../dist"
|
"frontendDist": "../dist"
|
||||||
},
|
},
|
||||||
@@ -37,13 +37,12 @@
|
|||||||
],
|
],
|
||||||
"externalBin": [
|
"externalBin": [
|
||||||
"binaries/yt-dlp",
|
"binaries/yt-dlp",
|
||||||
"binaries/ffmpeg",
|
|
||||||
"binaries/ffprobe",
|
|
||||||
"binaries/aria2c",
|
"binaries/aria2c",
|
||||||
"binaries/deno"
|
"binaries/deno"
|
||||||
],
|
],
|
||||||
"linux": {
|
"linux": {
|
||||||
"deb": {
|
"deb": {
|
||||||
|
"depends": ["ffmpeg"],
|
||||||
"files": {
|
"files": {
|
||||||
"/etc/opt/chrome/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
"/etc/opt/chrome/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
||||||
"/etc/chromium/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
"/etc/chromium/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
||||||
@@ -55,6 +54,7 @@
|
|||||||
"rpm": {
|
"rpm": {
|
||||||
"epoch": 0,
|
"epoch": 0,
|
||||||
"release": "1",
|
"release": "1",
|
||||||
|
"depends": ["ffmpeg"],
|
||||||
"files": {
|
"files": {
|
||||||
"/etc/opt/chrome/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
"/etc/opt/chrome/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
||||||
"/etc/chromium/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
"/etc/chromium/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"identifier": "com.neosubhamoy.neodlp",
|
"identifier": "com.neosubhamoy.neodlp",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "cargo build --target=x86_64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && node makeFilesExecutable.js && npm run dev",
|
"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 && node makeFilesExecutable.js && npm run build",
|
"beforeBuildCommand": "cargo build --release --target=x86_64-unknown-linux-gnu --manifest-path=./src-tauri/msghost/Cargo.toml && npm run build",
|
||||||
"devUrl": "http://localhost:1420",
|
"devUrl": "http://localhost:1420",
|
||||||
"frontendDist": "../dist"
|
"frontendDist": "../dist"
|
||||||
},
|
},
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
},
|
},
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"active": true,
|
"active": true,
|
||||||
"targets": ["deb", "rpm"],
|
"targets": ["deb", "rpm", "appimage"],
|
||||||
"createUpdaterArtifacts": true,
|
"createUpdaterArtifacts": true,
|
||||||
"licenseFile": "../LICENSE",
|
"licenseFile": "../LICENSE",
|
||||||
"icon": [
|
"icon": [
|
||||||
@@ -37,13 +37,12 @@
|
|||||||
],
|
],
|
||||||
"externalBin": [
|
"externalBin": [
|
||||||
"binaries/yt-dlp",
|
"binaries/yt-dlp",
|
||||||
"binaries/ffmpeg",
|
|
||||||
"binaries/ffprobe",
|
|
||||||
"binaries/aria2c",
|
"binaries/aria2c",
|
||||||
"binaries/deno"
|
"binaries/deno"
|
||||||
],
|
],
|
||||||
"linux": {
|
"linux": {
|
||||||
"deb": {
|
"deb": {
|
||||||
|
"depends": ["ffmpeg"],
|
||||||
"files": {
|
"files": {
|
||||||
"/etc/opt/chrome/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
"/etc/opt/chrome/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
||||||
"/etc/chromium/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
"/etc/chromium/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
||||||
@@ -55,6 +54,7 @@
|
|||||||
"rpm": {
|
"rpm": {
|
||||||
"epoch": 0,
|
"epoch": 0,
|
||||||
"release": "1",
|
"release": "1",
|
||||||
|
"depends": ["ffmpeg"],
|
||||||
"files": {
|
"files": {
|
||||||
"/etc/opt/chrome/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
"/etc/opt/chrome/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
||||||
"/etc/chromium/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
"/etc/chromium/native-messaging-hosts/com.neosubhamoy.neodlp.json": "./resources/msghost-manifest/linux/chrome.json",
|
||||||
@@ -62,6 +62,12 @@
|
|||||||
"/usr/bin/neodlp-msghost": "./target/x86_64-unknown-linux-gnu/release/neodlp-msghost",
|
"/usr/bin/neodlp-msghost": "./target/x86_64-unknown-linux-gnu/release/neodlp-msghost",
|
||||||
"/etc/xdg/autostart/neodlp-autostart.desktop": "./resources/autostart/linux/autostart.desktop"
|
"/etc/xdg/autostart/neodlp-autostart.desktop": "./resources/autostart/linux/autostart.desktop"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"appimage": {
|
||||||
|
"files": {
|
||||||
|
"/usr/bin/ffmpeg": "./binaries/ffmpeg-x86_64-unknown-linux-gnu",
|
||||||
|
"/usr/bin/ffprobe": "./binaries/ffprobe-x86_64-unknown-linux-gnu"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"identifier": "com.neosubhamoy.neodlp",
|
"identifier": "com.neosubhamoy.neodlp",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "cargo build --target=aarch64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && node makeFilesExecutable.js && npm run dev",
|
"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 && node makeFilesExecutable.js && npm run build",
|
"beforeBuildCommand": "cargo build --release --target=aarch64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && npm run build",
|
||||||
"devUrl": "http://localhost:1420",
|
"devUrl": "http://localhost:1420",
|
||||||
"frontendDist": "../dist"
|
"frontendDist": "../dist"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"identifier": "com.neosubhamoy.neodlp",
|
"identifier": "com.neosubhamoy.neodlp",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "cargo build --target=x86_64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && node makeFilesExecutable.js && npm run dev",
|
"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 && node makeFilesExecutable.js && npm run build",
|
"beforeBuildCommand": "cargo build --release --target=x86_64-apple-darwin --manifest-path=./src-tauri/msghost/Cargo.toml && npm run build",
|
||||||
"devUrl": "http://localhost:1420",
|
"devUrl": "http://localhost:1420",
|
||||||
"frontendDist": "../dist"
|
"frontendDist": "../dist"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -44,8 +44,8 @@
|
|||||||
],
|
],
|
||||||
"resources": {
|
"resources": {
|
||||||
"target/release/neodlp-msghost.exe": "neodlp-msghost.exe",
|
"target/release/neodlp-msghost.exe": "neodlp-msghost.exe",
|
||||||
"resources/msghost-manifest/windows/chrome.json": "neodlp-msghost.json",
|
"resources/msghost-manifest/windows/chrome.json": "chrome.json",
|
||||||
"resources/msghost-manifest/windows/firefox.json": "neodlp-msghost-moz.json"
|
"resources/msghost-manifest/windows/firefox.json": "firefox.json"
|
||||||
},
|
},
|
||||||
"windows": {
|
"windows": {
|
||||||
"wix": {
|
"wix": {
|
||||||
|
|||||||
98
src/App.tsx
@@ -29,6 +29,7 @@ import { toast } from "sonner";
|
|||||||
import { useLogger } from "@/helpers/use-logger";
|
import { useLogger } from "@/helpers/use-logger";
|
||||||
import { DownloadConfiguration } from "@/types/settings";
|
import { DownloadConfiguration } from "@/types/settings";
|
||||||
import { ulid } from "ulid";
|
import { ulid } from "ulid";
|
||||||
|
import { sendNotification } from '@tauri-apps/plugin-notification';
|
||||||
|
|
||||||
export default function App({ children }: { children: React.ReactNode }) {
|
export default function App({ children }: { children: React.ReactNode }) {
|
||||||
const { data: downloadStates, isSuccess: isSuccessFetchingDownloadStates } = useFetchAllDownloadStates();
|
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 ALWAYS_REENCODE_VIDEO = useSettingsPageStatesStore(state => state.settings.always_reencode_video);
|
||||||
const EMBED_VIDEO_METADATA = useSettingsPageStatesStore(state => state.settings.embed_video_metadata);
|
const EMBED_VIDEO_METADATA = useSettingsPageStatesStore(state => state.settings.embed_video_metadata);
|
||||||
const EMBED_AUDIO_METADATA = useSettingsPageStatesStore(state => state.settings.embed_audio_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 EMBED_AUDIO_THUMBNAIL = useSettingsPageStatesStore(state => state.settings.embed_audio_thumbnail);
|
||||||
const USE_COOKIES = useSettingsPageStatesStore(state => state.settings.use_cookies);
|
const USE_COOKIES = useSettingsPageStatesStore(state => state.settings.use_cookies);
|
||||||
const IMPORT_COOKIES_FROM = useSettingsPageStatesStore(state => state.settings.import_cookies_from);
|
const IMPORT_COOKIES_FROM = useSettingsPageStatesStore(state => state.settings.import_cookies_from);
|
||||||
@@ -88,6 +90,12 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
const USE_CUSTOM_COMMANDS = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
|
const USE_CUSTOM_COMMANDS = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
|
||||||
const CUSTOM_COMMANDS = useSettingsPageStatesStore(state => state.settings.custom_commands);
|
const CUSTOM_COMMANDS = useSettingsPageStatesStore(state => state.settings.custom_commands);
|
||||||
const FILENAME_TEMPLATE = useSettingsPageStatesStore(state => state.settings.filename_template);
|
const FILENAME_TEMPLATE = useSettingsPageStatesStore(state => state.settings.filename_template);
|
||||||
|
const DEBUG_MODE = useSettingsPageStatesStore(state => state.settings.debug_mode);
|
||||||
|
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 isErrored = useDownloaderPageStatesStore((state) => state.isErrored);
|
||||||
const isErrorExpected = useDownloaderPageStatesStore((state) => state.isErrorExpected);
|
const isErrorExpected = useDownloaderPageStatesStore((state) => state.isErrorExpected);
|
||||||
@@ -99,6 +107,7 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
const appWindow = getCurrentWebviewWindow()
|
const appWindow = getCurrentWebviewWindow()
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const LOG = useLogger();
|
const LOG = useLogger();
|
||||||
|
const currentPlatform = platform();
|
||||||
const { updateYtDlp } = useYtDlpUpdater();
|
const { updateYtDlp } = useYtDlpUpdater();
|
||||||
const { registerToMac } = useMacOsRegisterer();
|
const { registerToMac } = useMacOsRegisterer();
|
||||||
const { checkForAppUpdate } = useAppUpdater();
|
const { checkForAppUpdate } = useAppUpdater();
|
||||||
@@ -120,6 +129,7 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
const isProcessingQueueRef = useRef(false);
|
const isProcessingQueueRef = useRef(false);
|
||||||
const lastProcessedDownloadIdRef = useRef<string | null>(null);
|
const lastProcessedDownloadIdRef = useRef<string | null>(null);
|
||||||
const hasRunYtDlpAutoUpdateRef = useRef(false);
|
const hasRunYtDlpAutoUpdateRef = useRef(false);
|
||||||
|
const hasRunAppUpdateCheckRef = useRef(false);
|
||||||
const isRegisteredToMacOsRef = 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> => {
|
const fetchVideoMetadata = async (url: string, formatId?: string, playlistIndex?: string, selectedSubtitles?: string | null, resumeState?: DownloadState, downloadConfig?: DownloadConfiguration): Promise<RawVideoInfo | null> => {
|
||||||
@@ -294,11 +304,22 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
'--format',
|
'--format',
|
||||||
selectedFormat,
|
selectedFormat,
|
||||||
'--no-mtime',
|
'--no-mtime',
|
||||||
'--no-warnings',
|
|
||||||
'--retries',
|
'--retries',
|
||||||
MAX_RETRIES.toString(),
|
MAX_RETRIES.toString(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (currentPlatform === '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)) {
|
||||||
|
args.push('--no-warnings');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEBUG_MODE && LOG_VERBOSE) {
|
||||||
|
args.push('--verbose');
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedSubtitles) {
|
if (selectedSubtitles) {
|
||||||
args.push('--embed-subs', '--sub-lang', selectedSubtitles);
|
args.push('--embed-subs', '--sub-lang', selectedSubtitles);
|
||||||
}
|
}
|
||||||
@@ -358,21 +379,27 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
let embedMetadata = 0;
|
let embedMetadata = 0;
|
||||||
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && (downloadConfig.embed_metadata || resumeState?.embed_metadata || EMBED_VIDEO_METADATA || EMBED_AUDIO_METADATA)) {
|
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 shouldEmbedMetaForVideo = (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 shouldEmbedMetaForAudio = 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 shouldEmbedMetaForUnknown = fileType === 'unknown' && (downloadConfig.embed_metadata || resumeState?.embed_metadata);
|
||||||
|
|
||||||
if (shouldEmbedForUnknown || shouldEmbedForVideo || shouldEmbedForAudio) {
|
if (shouldEmbedMetaForUnknown || shouldEmbedMetaForVideo || shouldEmbedMetaForAudio) {
|
||||||
embedMetadata = 1;
|
embedMetadata = 1;
|
||||||
args.push('--embed-metadata');
|
args.push('--embed-metadata');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let embedThumbnail = 0;
|
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))) {
|
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;
|
embedThumbnail = 1;
|
||||||
args.push('--embed-thumbnail');
|
args.push('--embed-thumbnail');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && USE_PROXY && PROXY_URL) {
|
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && USE_PROXY && PROXY_URL) {
|
||||||
args.push('--proxy', PROXY_URL);
|
args.push('--proxy', PROXY_URL);
|
||||||
@@ -400,13 +427,13 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
let sponsorblockRemove = null;
|
let sponsorblockRemove = null;
|
||||||
let sponsorblockMark = null;
|
let sponsorblockMark = null;
|
||||||
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && (USE_SPONSORBLOCK || (resumeState?.sponsorblock_remove || resumeState?.sponsorblock_mark))) {
|
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && ((downloadConfig.sponsorblock && downloadConfig.sponsorblock !== 'auto') || resumeState?.sponsorblock_remove || resumeState?.sponsorblock_mark || USE_SPONSORBLOCK)) {
|
||||||
if (SPONSORBLOCK_MODE === 'remove' || resumeState?.sponsorblock_remove) {
|
if (downloadConfig?.sponsorblock === 'remove' || resumeState?.sponsorblock_remove || (SPONSORBLOCK_MODE === 'remove' && !downloadConfig.sponsorblock)) {
|
||||||
sponsorblockRemove = resumeState?.sponsorblock_remove || (SPONSORBLOCK_REMOVE === 'custom' ? (
|
sponsorblockRemove = resumeState?.sponsorblock_remove || (SPONSORBLOCK_REMOVE === 'custom' ? (
|
||||||
SPONSORBLOCK_REMOVE_CATEGORIES.length > 0 ? SPONSORBLOCK_REMOVE_CATEGORIES.join(',') : 'default'
|
SPONSORBLOCK_REMOVE_CATEGORIES.length > 0 ? SPONSORBLOCK_REMOVE_CATEGORIES.join(',') : 'default'
|
||||||
) : (SPONSORBLOCK_REMOVE));
|
) : (SPONSORBLOCK_REMOVE));
|
||||||
args.push('--sponsorblock-remove', sponsorblockRemove);
|
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' ? (
|
sponsorblockMark = resumeState?.sponsorblock_mark || (SPONSORBLOCK_MARK === 'custom' ? (
|
||||||
SPONSORBLOCK_MARK_CATEGORIES.length > 0 ? SPONSORBLOCK_MARK_CATEGORIES.join(',') : 'default'
|
SPONSORBLOCK_MARK_CATEGORIES.length > 0 ? SPONSORBLOCK_MARK_CATEGORIES.join(',') : 'default'
|
||||||
) : (SPONSORBLOCK_MARK));
|
) : (SPONSORBLOCK_MARK));
|
||||||
@@ -456,8 +483,8 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
command.stdout.on('data', line => {
|
command.stdout.on('data', line => {
|
||||||
if (line.startsWith('status:') || line.startsWith('[#')) {
|
if (line.startsWith('status:') || line.startsWith('[#')) {
|
||||||
console.log(line);
|
// console.log(line);
|
||||||
LOG.info(`YT-DLP Download ${downloadId}`, line);
|
if (DEBUG_MODE && LOG_PROGRESS) LOG.progress(`YT-DLP Download ${downloadId}`, line);
|
||||||
const currentProgress = parseProgressLine(line);
|
const currentProgress = parseProgressLine(line);
|
||||||
const state: DownloadState = {
|
const state: DownloadState = {
|
||||||
download_id: downloadId,
|
download_id: downloadId,
|
||||||
@@ -517,7 +544,7 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
console.log(line);
|
// console.log(line);
|
||||||
if (line.trim() !== '') LOG.info(`YT-DLP Download ${downloadId}`, line);
|
if (line.trim() !== '') LOG.info(`YT-DLP Download ${downloadId}`, line);
|
||||||
|
|
||||||
if (line.startsWith('Finalpath: ')) {
|
if (line.startsWith('Finalpath: ')) {
|
||||||
@@ -525,8 +552,8 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
const downloadedFileExt = downloadFilePath.split('.').pop();
|
const downloadedFileExt = downloadFilePath.split('.').pop();
|
||||||
|
|
||||||
// Update completion status after a short delay to ensure database states are propagated correctly
|
// 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...`);
|
console.log(`Download completed with ID: ${downloadId}, updating filepath and status after 1.5s delay...`);
|
||||||
setTimeout(() => {
|
setTimeout(async () => {
|
||||||
LOG.info('NEODLP', `yt-dlp download completed with id: ${downloadId}`);
|
LOG.info('NEODLP', `yt-dlp download completed with id: ${downloadId}`);
|
||||||
downloadFilePathUpdater.mutate({ download_id: downloadId, filepath: downloadFilePath as string, ext: downloadedFileExt as string }, {
|
downloadFilePathUpdater.mutate({ download_id: downloadId, filepath: downloadFilePath as string, ext: downloadedFileExt as string }, {
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
@@ -547,7 +574,18 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
console.error("Failed to update download status:", error);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -648,6 +686,7 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
if (!ongoingDownloads || ongoingDownloads && ongoingDownloads?.length < MAX_PARALLEL_DOWNLOADS) {
|
if (!ongoingDownloads || ongoingDownloads && ongoingDownloads?.length < MAX_PARALLEL_DOWNLOADS) {
|
||||||
LOG.info('NEODLP', `Starting yt-dlp download with args: ${args.join(' ')}`);
|
LOG.info('NEODLP', `Starting yt-dlp download with args: ${args.join(' ')}`);
|
||||||
|
if(!DEBUG_MODE || (DEBUG_MODE && !LOG_PROGRESS)) LOG.warning('NEODLP', `Progress logs are hidden. Enable 'Debug Mode > Log Progress' in Settings to unhide.`);
|
||||||
const child = await command.spawn();
|
const child = await command.spawn();
|
||||||
processPid = child.pid;
|
processPid = child.pid;
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@@ -725,6 +764,7 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
output_format: null,
|
output_format: null,
|
||||||
embed_metadata: null,
|
embed_metadata: null,
|
||||||
embed_thumbnail: null,
|
embed_thumbnail: null,
|
||||||
|
sponsorblock: null,
|
||||||
custom_command: null
|
custom_command: null
|
||||||
},
|
},
|
||||||
downloadState.subtitle_id,
|
downloadState.subtitle_id,
|
||||||
@@ -827,6 +867,7 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
output_format: null,
|
output_format: null,
|
||||||
embed_metadata: null,
|
embed_metadata: null,
|
||||||
embed_thumbnail: null,
|
embed_thumbnail: null,
|
||||||
|
sponsorblock: null,
|
||||||
custom_command: null
|
custom_command: null
|
||||||
},
|
},
|
||||||
downloadToStart.subtitle_id,
|
downloadToStart.subtitle_id,
|
||||||
@@ -852,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
|
// Prevent app from closing
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleCloseRequested = (event: any) => {
|
const handleCloseRequested = (event: any) => {
|
||||||
@@ -1008,6 +1042,24 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
fetchYtDlpVersion();
|
fetchYtDlpVersion();
|
||||||
}, [ytDlpVersion, setYtDlpVersion]);
|
}, [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
|
// Check for yt-dlp auto-update
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Only run once when both settings and KV pairs are loaded
|
// Only run once when both settings and KV pairs are loaded
|
||||||
@@ -1030,7 +1082,6 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
const YTDLP_UPDATE_INTERVAL = 86400000 // 24H;
|
const YTDLP_UPDATE_INTERVAL = 86400000 // 24H;
|
||||||
if (YTDLP_AUTO_UPDATE && (ytDlpUpdateLastCheck === null || currentTimestamp - ytDlpUpdateLastCheck > YTDLP_UPDATE_INTERVAL)) {
|
if (YTDLP_AUTO_UPDATE && (ytDlpUpdateLastCheck === null || currentTimestamp - ytDlpUpdateLastCheck > YTDLP_UPDATE_INTERVAL)) {
|
||||||
console.log("Running auto-update for yt-dlp...");
|
console.log("Running auto-update for yt-dlp...");
|
||||||
LOG.info('NEODLP', 'Updating yt-dlp to latest version (triggered because auto-update is enabled)');
|
|
||||||
updateYtDlp();
|
updateYtDlp();
|
||||||
} else {
|
} else {
|
||||||
console.log("Skipping yt-dlp auto-update, either disabled or recently updated.");
|
console.log("Skipping yt-dlp auto-update, either disabled or recently updated.");
|
||||||
@@ -1054,7 +1105,6 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
appVersion: appVersion,
|
appVersion: appVersion,
|
||||||
registeredVersion: macOsRegisteredVersion
|
registeredVersion: macOsRegisteredVersion
|
||||||
});
|
});
|
||||||
const currentPlatform = platform();
|
|
||||||
if (currentPlatform === 'macos' && (!macOsRegisteredVersion || macOsRegisteredVersion !== appVersion)) {
|
if (currentPlatform === 'macos' && (!macOsRegisteredVersion || macOsRegisteredVersion !== appVersion)) {
|
||||||
console.log("Running MacOS auto registration...");
|
console.log("Running MacOS auto registration...");
|
||||||
LOG.info('NEODLP', 'Running macOS registration');
|
LOG.info('NEODLP', 'Running macOS registration');
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default function Navbar() {
|
|||||||
const logs = useLogger().getLogs();
|
const logs = useLogger().getLogs();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="flex justify-between items-center py-3 px-4 sticky top-0 backdrop-blur supports-[backdrop-filter]:bg-background/60 border-b z-50">
|
<nav className="flex justify-between items-center py-3 px-4 sticky top-0 backdrop-blur supports-backdrop-filter:bg-background/60 border-b z-50">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<SidebarTrigger />
|
<SidebarTrigger />
|
||||||
<h1 className="text-lg text-primary font-semibold ml-4">{getRouteName(location.pathname)}</h1>
|
<h1 className="text-lg text-primary font-semibold ml-4">{getRouteName(location.pathname)}</h1>
|
||||||
@@ -41,7 +41,7 @@ export default function Navbar() {
|
|||||||
<p className="text-sm text-muted-foreground">NO LOGS TO SHOW!</p>
|
<p className="text-sm text-muted-foreground">NO LOGS TO SHOW!</p>
|
||||||
) : (
|
) : (
|
||||||
logs.slice().reverse().map((log, index) => (
|
logs.slice().reverse().map((log, index) => (
|
||||||
<div key={index} className={`flex flex-col ${log.level === 'error' ? 'text-red-500' : log.level === 'warning' ? 'text-amber-500' : log.level === 'debug' ? 'text-sky-500' : 'text-foreground'}`}>
|
<div key={index} className={`flex flex-col ${log.level === 'error' ? 'text-red-500' : log.level === 'warning' ? 'text-amber-500' : log.level === 'debug' ? 'text-sky-500' : log.level === 'progress' ? 'text-emerald-500' : 'text-foreground'}`}>
|
||||||
<p className="text-xs"><strong>{new Date(log.timestamp).toLocaleTimeString()}</strong> [{log.level.toUpperCase()}] <em>{log.context}</em> :</p>
|
<p className="text-xs"><strong>{new Date(log.timestamp).toLocaleTimeString()}</strong> [{log.level.toUpperCase()}] <em>{log.context}</em> :</p>
|
||||||
<p className="text-xs font-mono break-all">{log.message}</p>
|
<p className="text-xs font-mono break-all">{log.message}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
|
import { config } from "@/config";
|
||||||
import { check as checkAppUpdate, Update } from "@tauri-apps/plugin-updater";
|
import { check as checkAppUpdate, Update } from "@tauri-apps/plugin-updater";
|
||||||
import { relaunch as relaunchApp } from "@tauri-apps/plugin-process";
|
import { relaunch as relaunchApp } from "@tauri-apps/plugin-process";
|
||||||
import { useSettingsPageStatesStore } from "@/services/store";
|
import { useSettingsPageStatesStore } from "@/services/store";
|
||||||
|
import { useLogger } from "@/helpers/use-logger";
|
||||||
|
import { sendNotification } from '@tauri-apps/plugin-notification';
|
||||||
|
|
||||||
export default function useAppUpdater() {
|
export default function useAppUpdater() {
|
||||||
const setIsCheckingAppUpdate = useSettingsPageStatesStore(state => state.setIsCheckingAppUpdate);
|
const setIsCheckingAppUpdate = useSettingsPageStatesStore(state => state.setIsCheckingAppUpdate);
|
||||||
const setAppUpdate = useSettingsPageStatesStore(state => state.setAppUpdate);
|
const setAppUpdate = useSettingsPageStatesStore(state => state.setAppUpdate);
|
||||||
const setIsUpdating = useSettingsPageStatesStore(state => state.setIsUpdatingApp);
|
const setIsUpdating = useSettingsPageStatesStore(state => state.setIsUpdatingApp);
|
||||||
const setDownloadProgress = useSettingsPageStatesStore(state => state.setAppUpdateDownloadProgress);
|
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 () => {
|
const checkForAppUpdate = async () => {
|
||||||
setIsCheckingAppUpdate(true);
|
setIsCheckingAppUpdate(true);
|
||||||
@@ -15,6 +21,13 @@ export default function useAppUpdater() {
|
|||||||
if (update) {
|
if (update) {
|
||||||
setAppUpdate(update);
|
setAppUpdate(update);
|
||||||
console.log(`app update available v${update.version}`);
|
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) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -25,6 +38,7 @@ export default function useAppUpdater() {
|
|||||||
|
|
||||||
const downloadAndInstallAppUpdate = async (update: Update) => {
|
const downloadAndInstallAppUpdate = async (update: Update) => {
|
||||||
setIsUpdating(true);
|
setIsUpdating(true);
|
||||||
|
LOG.info('NEODLP', `Downloading and installing app update v${update.version}`);
|
||||||
let downloaded = 0;
|
let downloaded = 0;
|
||||||
let contentLength: number | undefined = 0;
|
let contentLength: number | undefined = 0;
|
||||||
await update.downloadAndInstall((event) => {
|
await update.downloadAndInstall((event) => {
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ export function useLogger() {
|
|||||||
debug: (context: string, message: string) => {
|
debug: (context: string, message: string) => {
|
||||||
addLog({ timestamp: Date.now(), level: 'debug', context, message });
|
addLog({ timestamp: Date.now(), level: 'debug', context, message });
|
||||||
},
|
},
|
||||||
|
progress: (context: string, message: string) => {
|
||||||
|
addLog({ timestamp: Date.now(), level: 'progress', context, message });
|
||||||
|
},
|
||||||
getLogs: () => logs,
|
getLogs: () => logs,
|
||||||
clearLogs,
|
clearLogs,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { useSettingsPageStatesStore } from "@/services/store";
|
import { useSettingsPageStatesStore } from "@/services/store";
|
||||||
import { useKvPairs } from "@/helpers/use-kvpairs";
|
import { useKvPairs } from "@/helpers/use-kvpairs";
|
||||||
import { Command } from "@tauri-apps/plugin-shell";
|
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 { platform } from "@tauri-apps/plugin-os";
|
||||||
|
import { useLogger } from "@/helpers/use-logger";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
export function useYtDlpUpdater() {
|
export function useYtDlpUpdater() {
|
||||||
const { saveKvPair } = useKvPairs();
|
const { saveKvPair } = useKvPairs();
|
||||||
@@ -9,22 +13,49 @@ export function useYtDlpUpdater() {
|
|||||||
const setIsUpdatingYtDlp = useSettingsPageStatesStore((state) => state.setIsUpdatingYtDlp);
|
const setIsUpdatingYtDlp = useSettingsPageStatesStore((state) => state.setIsUpdatingYtDlp);
|
||||||
const setYtDlpVersion = useSettingsPageStatesStore((state) => state.setYtDlpVersion);
|
const setYtDlpVersion = useSettingsPageStatesStore((state) => state.setYtDlpVersion);
|
||||||
const currentPlatform = platform();
|
const currentPlatform = platform();
|
||||||
|
const LOG = useLogger();
|
||||||
|
|
||||||
const updateYtDlp = async () => {
|
const updateYtDlp = async () => {
|
||||||
const CURRENT_TIMESTAMP = Date.now();
|
const CURRENT_TIMESTAMP = Date.now();
|
||||||
setIsUpdatingYtDlp(true);
|
setIsUpdatingYtDlp(true);
|
||||||
|
LOG.info('NEODLP', 'Updating yt-dlp to latest version');
|
||||||
try {
|
try {
|
||||||
const command = currentPlatform === 'linux' ? Command.create('pkexec', ['yt-dlp', '--update-to', ytDlpUpdateChannel]) : Command.sidecar('binaries/yt-dlp', ['--update-to', ytDlpUpdateChannel]);
|
const command = currentPlatform === 'linux' ? 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);
|
||||||
|
LOG.info('NEODLP', "yt-dlp updated successfully");
|
||||||
saveKvPair('ytdlp_update_last_check', CURRENT_TIMESTAMP);
|
saveKvPair('ytdlp_update_last_check', CURRENT_TIMESTAMP);
|
||||||
setYtDlpVersion(null);
|
setYtDlpVersion(null);
|
||||||
|
toast.success("Update successful", { description: "yt-dlp has been updated successfully." });
|
||||||
} else {
|
} 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);
|
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) {
|
} catch (e) {
|
||||||
console.error('Failed to update yt-dlp:', 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 {
|
} finally {
|
||||||
setIsUpdatingYtDlp(false);
|
setIsUpdatingYtDlp(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { toast } from "sonner";
|
|||||||
import { useAppContext } from "@/providers/appContextProvider";
|
import { useAppContext } from "@/providers/appContextProvider";
|
||||||
import { useCurrentVideoMetadataStore, useDownloaderPageStatesStore, useSettingsPageStatesStore } from "@/services/store";
|
import { useCurrentVideoMetadataStore, useDownloaderPageStatesStore, useSettingsPageStatesStore } from "@/services/store";
|
||||||
import { determineFileType, fileFormatFilter, formatBitrate, formatDurationString, formatFileSize, formatReleaseDate, formatYtStyleCount, isObjEmpty, sortByBitrate } from "@/utils";
|
import { determineFileType, fileFormatFilter, formatBitrate, formatDurationString, formatFileSize, formatReleaseDate, formatYtStyleCount, isObjEmpty, sortByBitrate } from "@/utils";
|
||||||
import { Calendar, Clock, DownloadCloud, Eye, Info, Loader2, Music, ThumbsUp, Video, File, ListVideo, PackageSearch, AlertCircleIcon, X, Settings2 } from "lucide-react";
|
import { Calendar, Clock, DownloadCloud, Eye, Info, Loader2, Music, ThumbsUp, Video, File, ListVideo, PackageSearch, AlertCircleIcon, X, Settings2, Clipboard } from "lucide-react";
|
||||||
import { FormatSelectionGroup, FormatSelectionGroupItem } from "@/components/custom/formatSelectionGroup";
|
import { FormatSelectionGroup, FormatSelectionGroupItem } from "@/components/custom/formatSelectionGroup";
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { ToggleGroup, ToggleGroupItem } from "@/components/custom/legacyToggleGroup";
|
import { ToggleGroup, ToggleGroupItem } from "@/components/custom/legacyToggleGroup";
|
||||||
@@ -29,6 +29,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
|
|||||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import { readText } from '@tauri-apps/plugin-clipboard-manager';
|
||||||
|
|
||||||
const searchFormSchema = z.object({
|
const searchFormSchema = z.object({
|
||||||
url: z.url({
|
url: z.url({
|
||||||
@@ -79,6 +80,7 @@ export default function DownloaderPage() {
|
|||||||
const audioFormat = useSettingsPageStatesStore(state => state.settings.audio_format);
|
const audioFormat = useSettingsPageStatesStore(state => state.settings.audio_format);
|
||||||
const embedVideoMetadata = useSettingsPageStatesStore(state => state.settings.embed_video_metadata);
|
const embedVideoMetadata = useSettingsPageStatesStore(state => state.settings.embed_video_metadata);
|
||||||
const embedAudioMetadata = useSettingsPageStatesStore(state => state.settings.embed_audio_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 embedAudioThumbnail = useSettingsPageStatesStore(state => state.settings.embed_audio_thumbnail);
|
||||||
const useCustomCommands = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
|
const useCustomCommands = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
|
||||||
const customCommands = useSettingsPageStatesStore(state => state.settings.custom_commands);
|
const customCommands = useSettingsPageStatesStore(state => state.settings.custom_commands);
|
||||||
@@ -391,6 +393,36 @@ export default function DownloaderPage() {
|
|||||||
<X className="size-4" />
|
<X className="size-4" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
{!isMetadataLoading && !videoUrl && (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="icon"
|
||||||
|
disabled={isMetadataLoading}
|
||||||
|
onClick={async () => {
|
||||||
|
const text = await readText();
|
||||||
|
if (text) {
|
||||||
|
searchForm.setValue("url", text);
|
||||||
|
setVideoUrl(text);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Clipboard className="size-4" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{!isMetadataLoading && videoUrl && (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
disabled={isMetadataLoading}
|
||||||
|
onClick={() => {
|
||||||
|
searchForm.setValue("url", '');
|
||||||
|
setVideoUrl('');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<X className="size-4" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!videoUrl || Object.keys(searchFormErrors).length > 0 || isMetadataLoading}
|
disabled={!videoUrl || Object.keys(searchFormErrors).length > 0 || isMetadataLoading}
|
||||||
@@ -465,6 +497,7 @@ export default function DownloaderPage() {
|
|||||||
setDownloadConfigurationKey('output_format', null);
|
setDownloadConfigurationKey('output_format', null);
|
||||||
setDownloadConfigurationKey('embed_metadata', null);
|
setDownloadConfigurationKey('embed_metadata', null);
|
||||||
setDownloadConfigurationKey('embed_thumbnail', null);
|
setDownloadConfigurationKey('embed_thumbnail', null);
|
||||||
|
setDownloadConfigurationKey('sponsorblock', null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@@ -514,6 +547,7 @@ export default function DownloaderPage() {
|
|||||||
setDownloadConfigurationKey('output_format', null);
|
setDownloadConfigurationKey('output_format', null);
|
||||||
setDownloadConfigurationKey('embed_metadata', null);
|
setDownloadConfigurationKey('embed_metadata', null);
|
||||||
setDownloadConfigurationKey('embed_thumbnail', null);
|
setDownloadConfigurationKey('embed_thumbnail', null);
|
||||||
|
setDownloadConfigurationKey('sponsorblock', null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p className="text-xs">Suggested</p>
|
<p className="text-xs">Suggested</p>
|
||||||
@@ -617,6 +651,7 @@ export default function DownloaderPage() {
|
|||||||
setDownloadConfigurationKey('output_format', null);
|
setDownloadConfigurationKey('output_format', null);
|
||||||
setDownloadConfigurationKey('embed_metadata', null);
|
setDownloadConfigurationKey('embed_metadata', null);
|
||||||
setDownloadConfigurationKey('embed_thumbnail', null);
|
setDownloadConfigurationKey('embed_thumbnail', null);
|
||||||
|
setDownloadConfigurationKey('sponsorblock', null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{videoOnlyFormats && videoOnlyFormats.length > 0 && audioOnlyFormats && audioOnlyFormats.length > 0 && (
|
{videoOnlyFormats && videoOnlyFormats.length > 0 && audioOnlyFormats && audioOnlyFormats.length > 0 && (
|
||||||
@@ -641,6 +676,7 @@ export default function DownloaderPage() {
|
|||||||
setDownloadConfigurationKey('output_format', null);
|
setDownloadConfigurationKey('output_format', null);
|
||||||
setDownloadConfigurationKey('embed_metadata', null);
|
setDownloadConfigurationKey('embed_metadata', null);
|
||||||
setDownloadConfigurationKey('embed_thumbnail', null);
|
setDownloadConfigurationKey('embed_thumbnail', null);
|
||||||
|
setDownloadConfigurationKey('sponsorblock', null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{audioOnlyFormats && audioOnlyFormats.length > 0 && videoOnlyFormats && videoOnlyFormats.length > 0 && (
|
{audioOnlyFormats && audioOnlyFormats.length > 0 && videoOnlyFormats && videoOnlyFormats.length > 0 && (
|
||||||
@@ -945,7 +981,7 @@ export default function DownloaderPage() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<span className="text-sm text-nowrap max-w-[30rem] xl:max-w-[50rem] overflow-hidden text-ellipsis">{videoMetadata._type === 'video' ? videoMetadata.title : videoMetadata._type === 'playlist' ? videoMetadata.entries[Number(selectedPlaylistVideoIndex) - 1].title : 'Unknown' }</span>
|
<span className="text-sm text-nowrap max-w-120 xl:max-w-200 overflow-hidden text-ellipsis">{videoMetadata._type === 'video' ? videoMetadata.title : videoMetadata._type === 'playlist' ? videoMetadata.entries[Number(selectedPlaylistVideoIndex) - 1].title : 'Unknown' }</span>
|
||||||
<span className="text-xs text-muted-foreground">{selectedFormatFinalMsg}</span>
|
<span className="text-xs text-muted-foreground">{selectedFormatFinalMsg}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1083,6 +1119,29 @@ export default function DownloaderPage() {
|
|||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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">
|
<div className="embeding-options">
|
||||||
<Label className="text-xs my-3">Embeding Options</Label>
|
<Label className="text-xs my-3">Embeding Options</Label>
|
||||||
<div className="flex items-center space-x-2 mt-3">
|
<div className="flex items-center space-x-2 mt-3">
|
||||||
@@ -1097,7 +1156,7 @@ export default function DownloaderPage() {
|
|||||||
<div className="flex items-center space-x-2 mt-3">
|
<div className="flex items-center space-x-2 mt-3">
|
||||||
<Switch
|
<Switch
|
||||||
id="embed-thumbnail"
|
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)}
|
onCheckedChange={(checked) => setDownloadConfigurationKey('embed_thumbnail', checked)}
|
||||||
disabled={useCustomCommands}
|
disabled={useCustomCommands}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Progress } from "@/components/ui/progress";
|
|||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useAppContext } from "@/providers/appContextProvider";
|
import { useAppContext } from "@/providers/appContextProvider";
|
||||||
import { useCurrentVideoMetadataStore, useDownloadActionStatesStore, useDownloadStatesStore, useLibraryPageStatesStore } from "@/services/store";
|
import { useCurrentVideoMetadataStore, useDownloadActionStatesStore, useDownloadStatesStore, useLibraryPageStatesStore, useSettingsPageStatesStore } from "@/services/store";
|
||||||
import { formatBitrate, formatCodec, formatDurationString, formatFileSize, formatSecToTimeString, formatSpeed } from "@/utils";
|
import { formatBitrate, formatCodec, formatDurationString, formatFileSize, formatSecToTimeString, formatSpeed } from "@/utils";
|
||||||
import { AudioLines, Clock, File, FileAudio2, FileQuestion, FileVideo2, FolderInput, ListVideo, Loader2, Music, Pause, Play, Search, Square, Trash2, Video, X } from "lucide-react";
|
import { AudioLines, Clock, File, FileAudio2, FileQuestion, FileVideo2, FolderInput, ListVideo, Loader2, Music, Pause, Play, Search, Square, Trash2, Video, X } from "lucide-react";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
@@ -34,6 +34,8 @@ export default function LibraryPage() {
|
|||||||
const setIsCancelingDownload = useDownloadActionStatesStore(state => state.setIsCancelingDownload);
|
const setIsCancelingDownload = useDownloadActionStatesStore(state => state.setIsCancelingDownload);
|
||||||
const setIsDeleteFileChecked = useDownloadActionStatesStore(state => state.setIsDeleteFileChecked);
|
const setIsDeleteFileChecked = useDownloadActionStatesStore(state => state.setIsDeleteFileChecked);
|
||||||
|
|
||||||
|
const debugMode = useSettingsPageStatesStore(state => state.settings.debug_mode);
|
||||||
|
|
||||||
const { pauseDownload, resumeDownload, cancelDownload } = useAppContext()
|
const { pauseDownload, resumeDownload, cancelDownload } = useAppContext()
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@@ -379,7 +381,7 @@ export default function LibraryPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="text-xs text-muted-foreground">{ state.download_status && (
|
<div className="text-xs text-muted-foreground">{ state.download_status && (
|
||||||
`${state.download_status === 'downloading' && state.status === 'finished' ? 'Processing' : state.download_status.charAt(0).toUpperCase() + state.download_status.slice(1)} ${state.download_id ? `• ID: ${state.download_id.toUpperCase()}` : ""} ${state.download_status === 'downloading' && state.status !== 'finished' && state.speed ? `• Speed: ${formatSpeed(state.speed)}` : ""} ${state.download_status === 'downloading' && state.eta ? `• ETA: ${formatSecToTimeString(state.eta)}` : ""}`
|
`${state.download_status === 'downloading' && state.status === 'finished' ? 'Processing' : state.download_status.charAt(0).toUpperCase() + state.download_status.slice(1)} ${debugMode && state.download_id ? `• ID: ${state.download_id.toUpperCase()}` : ""} ${state.download_status === 'downloading' && state.status !== 'finished' && state.speed ? `• Speed: ${formatSpeed(state.speed)}` : ""} ${state.download_status === 'downloading' && state.eta ? `• ETA: ${formatSecToTimeString(state.eta)}` : ""}`
|
||||||
)}</div>
|
)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex items-center gap-2 mt-2">
|
<div className="w-full flex items-center gap-2 mt-2">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Switch } from "@/components/ui/switch";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { ArrowDownToLine, ArrowRight, BrushCleaning, 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 { cn } from "@/lib/utils";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useTheme } from "@/providers/themeProvider";
|
import { useTheme } from "@/providers/themeProvider";
|
||||||
@@ -30,6 +30,7 @@ import { formatSpeed, generateID } from "@/utils";
|
|||||||
import { ToggleGroup, ToggleGroupItem } from "@/components/custom/legacyToggleGroup";
|
import { ToggleGroup, ToggleGroupItem } from "@/components/custom/legacyToggleGroup";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
|
import { isPermissionGranted, requestPermission } from '@tauri-apps/plugin-notification';
|
||||||
|
|
||||||
const websocketPortSchema = z.object({
|
const websocketPortSchema = z.object({
|
||||||
port: z.coerce.number<number>({
|
port: z.coerce.number<number>({
|
||||||
@@ -106,6 +107,7 @@ export default function SettingsPage() {
|
|||||||
const alwaysReencodeVideo = useSettingsPageStatesStore(state => state.settings.always_reencode_video);
|
const alwaysReencodeVideo = useSettingsPageStatesStore(state => state.settings.always_reencode_video);
|
||||||
const embedVideoMetadata = useSettingsPageStatesStore(state => state.settings.embed_video_metadata);
|
const embedVideoMetadata = useSettingsPageStatesStore(state => state.settings.embed_video_metadata);
|
||||||
const embedAudioMetadata = useSettingsPageStatesStore(state => state.settings.embed_audio_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 embedAudioThumbnail = useSettingsPageStatesStore(state => state.settings.embed_audio_thumbnail);
|
||||||
const useCookies = useSettingsPageStatesStore(state => state.settings.use_cookies);
|
const useCookies = useSettingsPageStatesStore(state => state.settings.use_cookies);
|
||||||
const importCookiesFrom = useSettingsPageStatesStore(state => state.settings.import_cookies_from);
|
const importCookiesFrom = useSettingsPageStatesStore(state => state.settings.import_cookies_from);
|
||||||
@@ -123,6 +125,13 @@ export default function SettingsPage() {
|
|||||||
const useCustomCommands = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
|
const useCustomCommands = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
|
||||||
const customCommands = useSettingsPageStatesStore(state => state.settings.custom_commands);
|
const customCommands = useSettingsPageStatesStore(state => state.settings.custom_commands);
|
||||||
const filenameTemplate = useSettingsPageStatesStore(state => state.settings.filename_template);
|
const filenameTemplate = useSettingsPageStatesStore(state => state.settings.filename_template);
|
||||||
|
const debugMode = useSettingsPageStatesStore(state => state.settings.debug_mode);
|
||||||
|
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 websocketPort = useSettingsPageStatesStore(state => state.settings.websocket_port);
|
||||||
const isChangingWebSocketPort = useSettingsPageStatesStore(state => state.isChangingWebSocketPort);
|
const isChangingWebSocketPort = useSettingsPageStatesStore(state => state.isChangingWebSocketPort);
|
||||||
@@ -520,14 +529,24 @@ export default function SettingsPage() {
|
|||||||
value="sponsorblock"
|
value="sponsorblock"
|
||||||
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground justify-start px-3 py-1.5 gap-2"
|
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>
|
><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
|
<TabsTrigger
|
||||||
key="commands"
|
key="commands"
|
||||||
value="commands"
|
value="commands"
|
||||||
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground justify-start px-3 py-1.5 gap-2"
|
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground justify-start px-3 py-1.5 gap-2"
|
||||||
><SquareTerminal className="size-4" /> Commands</TabsTrigger>
|
><SquareTerminal className="size-4" /> Commands</TabsTrigger>
|
||||||
|
<TabsTrigger
|
||||||
|
key="debug"
|
||||||
|
value="debug"
|
||||||
|
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground justify-start px-3 py-1.5 gap-2"
|
||||||
|
><Bug className="size-4" /> Debug</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
<div className="min-h-full flex flex-col max-w-[55%] w-full border-l border-border pl-4">
|
<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-[350px]">
|
<TabsContent key="general" value="general" className="flex flex-col gap-4 min-h-[425px]">
|
||||||
<div className="max-parallel-downloads">
|
<div className="max-parallel-downloads">
|
||||||
<h3 className="font-semibold">Max Parallel Downloads</h3>
|
<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>
|
<p className="text-xs text-muted-foreground mb-3">Set maximum number of allowed parallel downloads</p>
|
||||||
@@ -583,7 +602,7 @@ export default function SettingsPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent key="appearance" value="appearance" className="flex flex-col gap-4 min-h-[350px]">
|
<TabsContent key="appearance" value="appearance" className="flex flex-col gap-4 min-h-[425px]">
|
||||||
<div className="app-theme">
|
<div className="app-theme">
|
||||||
<h3 className="font-semibold">Theme</h3>
|
<h3 className="font-semibold">Theme</h3>
|
||||||
<p className="text-xs text-muted-foreground mb-3">Choose app interface theme</p>
|
<p className="text-xs text-muted-foreground mb-3">Choose app interface theme</p>
|
||||||
@@ -606,7 +625,7 @@ export default function SettingsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent key="folders" value="folders" className="flex flex-col gap-4 min-h-[350px]">
|
<TabsContent key="folders" value="folders" className="flex flex-col gap-4 min-h-[425px]">
|
||||||
<div className="download-dir">
|
<div className="download-dir">
|
||||||
<h3 className="font-semibold">Download Folder</h3>
|
<h3 className="font-semibold">Download Folder</h3>
|
||||||
<p className="text-xs text-muted-foreground mb-3">Set default download folder (directory)</p>
|
<p className="text-xs text-muted-foreground mb-3">Set default download folder (directory)</p>
|
||||||
@@ -696,7 +715,7 @@ export default function SettingsPage() {
|
|||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent key="formats" value="formats" className="flex flex-col gap-4 min-h-[350px]">
|
<TabsContent key="formats" value="formats" className="flex flex-col gap-4 min-h-[425px]">
|
||||||
<div className="video-format">
|
<div className="video-format">
|
||||||
<h3 className="font-semibold">Video Format</h3>
|
<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>
|
<p className="text-xs text-muted-foreground mb-3">Choose in which format the final video file will be saved</p>
|
||||||
@@ -764,8 +783,8 @@ export default function SettingsPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent key="metadata" value="metadata" className="flex flex-col gap-4 min-h-[350px]">
|
<TabsContent key="metadata" value="metadata" className="flex flex-col gap-4 min-h-[425px]">
|
||||||
<div className="embed-video-metadata">
|
<div className="embed-metadata">
|
||||||
<h3 className="font-semibold">Embed Metadata</h3>
|
<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>
|
<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">
|
<div className="flex items-center space-x-2 mb-3">
|
||||||
@@ -787,18 +806,30 @@ export default function SettingsPage() {
|
|||||||
<Label htmlFor="embed-audio-metadata">Audio</Label>
|
<Label htmlFor="embed-audio-metadata">Audio</Label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="embed-audio-thumbnail">
|
<div className="embed-thumbnail">
|
||||||
<h3 className="font-semibold">Embed Thumbnail in Audio</h3>
|
<h3 className="font-semibold">Embed Thumbnail</h3>
|
||||||
<p className="text-xs text-muted-foreground mb-3">Wheather to embed thumbnail in audio files (as cover art)</p>
|
<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
|
<Switch
|
||||||
id="embed-audio-thumbnail"
|
id="embed-audio-thumbnail"
|
||||||
checked={embedAudioThumbnail}
|
checked={embedAudioThumbnail}
|
||||||
onCheckedChange={(checked) => saveSettingsKey('embed_audio_thumbnail', checked)}
|
onCheckedChange={(checked) => saveSettingsKey('embed_audio_thumbnail', checked)}
|
||||||
disabled={useCustomCommands}
|
disabled={useCustomCommands}
|
||||||
/>
|
/>
|
||||||
|
<Label htmlFor="embed-audio-thumbnail">Audio</Label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent key="network" value="network" className="flex flex-col gap-4 min-h-[350px]">
|
<TabsContent key="network" value="network" className="flex flex-col gap-4 min-h-[425px]">
|
||||||
<div className="proxy">
|
<div className="proxy">
|
||||||
<h3 className="font-semibold">Proxy</h3>
|
<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>
|
<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>
|
||||||
@@ -893,7 +924,7 @@ export default function SettingsPage() {
|
|||||||
onCheckedChange={(checked) => saveSettingsKey('use_force_internet_protocol', checked)}
|
onCheckedChange={(checked) => saveSettingsKey('use_force_internet_protocol', checked)}
|
||||||
disabled={useCustomCommands}
|
disabled={useCustomCommands}
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="use-force-internet-protocol">Force</Label>
|
<Label htmlFor="use-force-internet-protocol">Force IPV</Label>
|
||||||
</div>
|
</div>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
orientation="horizontal"
|
orientation="horizontal"
|
||||||
@@ -914,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>
|
<Label className="text-xs text-muted-foreground">(Forced: {forceInternetProtocol === "ipv4" ? 'IPv4' : 'IPv6'}, Status: {useForceInternetProtocol && !useCustomCommands ? 'Enabled' : 'Disabled'})</Label>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent key="cookies" value="cookies" className="flex flex-col gap-4 min-h-[350px]">
|
<TabsContent key="cookies" value="cookies" className="flex flex-col gap-4 min-h-[425px]">
|
||||||
<div className="cookies">
|
<div className="cookies">
|
||||||
<h3 className="font-semibold">Cookies</h3>
|
<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>
|
<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>
|
||||||
@@ -1003,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>
|
<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>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent key="sponsorblock" value="sponsorblock" className="flex flex-col gap-4 min-h-[350px]">
|
<TabsContent key="sponsorblock" value="sponsorblock" className="flex flex-col gap-4 min-h-[425px]">
|
||||||
<div className="sponsorblock">
|
<div className="sponsorblock">
|
||||||
<h3 className="font-semibold">Sponsor Block</h3>
|
<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>
|
<p className="text-xs text-muted-foreground mb-3">Use sponsorblock to remove/mark unwanted segments in videos (sponsorships, intros, outros, etc.)</p>
|
||||||
@@ -1039,7 +1070,7 @@ export default function SettingsPage() {
|
|||||||
className="flex items-center gap-4"
|
className="flex items-center gap-4"
|
||||||
value={sponsorblockRemove}
|
value={sponsorblockRemove}
|
||||||
onValueChange={(value) => saveSettingsKey('sponsorblock_remove', value)}
|
onValueChange={(value) => saveSettingsKey('sponsorblock_remove', value)}
|
||||||
disabled={!useSponsorblock || sponsorblockMode !== "remove" || useCustomCommands}
|
disabled={/*!useSponsorblock || sponsorblockMode !== "remove" ||*/ useCustomCommands}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<RadioGroupItem value="default" id="sponsorblock-remove-default" />
|
<RadioGroupItem value="default" id="sponsorblock-remove-default" />
|
||||||
@@ -1060,7 +1091,7 @@ export default function SettingsPage() {
|
|||||||
className="flex flex-col items-start gap-2 mt-1"
|
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) : []}
|
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)}
|
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">
|
<div className="flex gap-2 flex-wrap items-center">
|
||||||
{sponsorblockCategories.map((category) => (
|
{sponsorblockCategories.map((category) => (
|
||||||
@@ -1086,7 +1117,7 @@ export default function SettingsPage() {
|
|||||||
className="flex items-center gap-4"
|
className="flex items-center gap-4"
|
||||||
value={sponsorblockMark}
|
value={sponsorblockMark}
|
||||||
onValueChange={(value) => saveSettingsKey('sponsorblock_mark', value)}
|
onValueChange={(value) => saveSettingsKey('sponsorblock_mark', value)}
|
||||||
disabled={!useSponsorblock || sponsorblockMode !== "mark" || useCustomCommands}
|
disabled={/*!useSponsorblock || sponsorblockMode !== "mark" ||*/ useCustomCommands}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<RadioGroupItem value="default" id="sponsorblock-mark-default" />
|
<RadioGroupItem value="default" id="sponsorblock-mark-default" />
|
||||||
@@ -1107,7 +1138,7 @@ export default function SettingsPage() {
|
|||||||
className="flex flex-col items-start gap-2 mt-1 mb-2"
|
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) : []}
|
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)}
|
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">
|
<div className="flex gap-2 flex-wrap items-center">
|
||||||
{sponsorblockCategories.map((category) => (
|
{sponsorblockCategories.map((category) => (
|
||||||
@@ -1127,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>
|
<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>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent key="commands" value="commands" className="flex flex-col gap-4 min-h-[350px]">
|
<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">
|
<div className="custom-commands">
|
||||||
<h3 className="font-semibold">Custom Commands</h3>
|
<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>
|
<p className="text-xs text-muted-foreground mb-3"> Run custom yt-dlp commands for your downloads</p>
|
||||||
@@ -1229,6 +1309,50 @@ export default function SettingsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
<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>
|
||||||
|
<div className="flex items-center space-x-2 mb-4">
|
||||||
|
<Switch
|
||||||
|
id="debug-mode"
|
||||||
|
checked={debugMode}
|
||||||
|
onCheckedChange={(checked) => saveSettingsKey('debug_mode', checked)}
|
||||||
|
/>
|
||||||
|
<Label htmlFor="debug-mode">Enable Debug Mode</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-2 mt-5">
|
||||||
|
<Label className="text-xs mb-1">Logging Options</Label>
|
||||||
|
<div className="flex items-center space-x-2 mb-1">
|
||||||
|
<Switch
|
||||||
|
id="log-verbose"
|
||||||
|
checked={logVerbose}
|
||||||
|
onCheckedChange={(checked) => saveSettingsKey('log_verbose', checked)}
|
||||||
|
disabled={!debugMode}
|
||||||
|
/>
|
||||||
|
<Label htmlFor="log-verbose">Verbose Logging</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center space-x-2 mb-1">
|
||||||
|
<Switch
|
||||||
|
id="log-warning"
|
||||||
|
checked={logWarning}
|
||||||
|
onCheckedChange={(checked) => saveSettingsKey('log_warning', checked)}
|
||||||
|
disabled={!debugMode}
|
||||||
|
/>
|
||||||
|
<Label htmlFor="log-warning">Log Warnings</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center space-x-2 mb-1">
|
||||||
|
<Switch
|
||||||
|
id="log-progress"
|
||||||
|
checked={logProgress}
|
||||||
|
onCheckedChange={(checked) => saveSettingsKey('log_progress', checked)}
|
||||||
|
disabled={!debugMode}
|
||||||
|
/>
|
||||||
|
<Label htmlFor="log-progress">Log Progress</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
</div>
|
</div>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export const useDownloaderPageStatesStore = create<DownloaderPageStatesStore>((s
|
|||||||
output_format: null,
|
output_format: null,
|
||||||
embed_metadata: null,
|
embed_metadata: null,
|
||||||
embed_thumbnail: null,
|
embed_thumbnail: null,
|
||||||
|
sponsorblock: null,
|
||||||
custom_command: null
|
custom_command: null
|
||||||
},
|
},
|
||||||
isErrored: false,
|
isErrored: false,
|
||||||
@@ -83,6 +84,7 @@ export const useDownloaderPageStatesStore = create<DownloaderPageStatesStore>((s
|
|||||||
output_format: null,
|
output_format: null,
|
||||||
embed_metadata: null,
|
embed_metadata: null,
|
||||||
embed_thumbnail: null,
|
embed_thumbnail: null,
|
||||||
|
sponsorblock: null,
|
||||||
custom_command: null
|
custom_command: null
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
@@ -163,6 +165,7 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
|
|||||||
always_reencode_video: false,
|
always_reencode_video: false,
|
||||||
embed_video_metadata: false,
|
embed_video_metadata: false,
|
||||||
embed_audio_metadata: true,
|
embed_audio_metadata: true,
|
||||||
|
embed_video_thumbnail: false,
|
||||||
embed_audio_thumbnail: true,
|
embed_audio_thumbnail: true,
|
||||||
use_cookies: false,
|
use_cookies: false,
|
||||||
import_cookies_from: 'browser',
|
import_cookies_from: 'browser',
|
||||||
@@ -180,6 +183,13 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
|
|||||||
use_custom_commands: false,
|
use_custom_commands: false,
|
||||||
custom_commands: [],
|
custom_commands: [],
|
||||||
filename_template: '%(title)s_%(resolution|unknown)s',
|
filename_template: '%(title)s_%(resolution|unknown)s',
|
||||||
|
debug_mode: false,
|
||||||
|
log_verbose: true,
|
||||||
|
log_warning: true,
|
||||||
|
log_progress: false,
|
||||||
|
enable_notifications: false,
|
||||||
|
update_notification: true,
|
||||||
|
download_completion_notification: false,
|
||||||
// extension settings
|
// extension settings
|
||||||
websocket_port: 53511
|
websocket_port: 53511
|
||||||
},
|
},
|
||||||
@@ -224,6 +234,7 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
|
|||||||
always_reencode_video: false,
|
always_reencode_video: false,
|
||||||
embed_video_metadata: false,
|
embed_video_metadata: false,
|
||||||
embed_audio_metadata: true,
|
embed_audio_metadata: true,
|
||||||
|
embed_video_thumbnail: false,
|
||||||
embed_audio_thumbnail: true,
|
embed_audio_thumbnail: true,
|
||||||
use_cookies: false,
|
use_cookies: false,
|
||||||
import_cookies_from: 'browser',
|
import_cookies_from: 'browser',
|
||||||
@@ -241,6 +252,13 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
|
|||||||
use_custom_commands: false,
|
use_custom_commands: false,
|
||||||
custom_commands: [],
|
custom_commands: [],
|
||||||
filename_template: '%(title)s_%(resolution|unknown)s',
|
filename_template: '%(title)s_%(resolution|unknown)s',
|
||||||
|
debug_mode: false,
|
||||||
|
log_verbose: true,
|
||||||
|
log_warning: true,
|
||||||
|
log_progress: false,
|
||||||
|
enable_notifications: false,
|
||||||
|
update_notification: true,
|
||||||
|
download_completion_notification: false,
|
||||||
// extension settings
|
// extension settings
|
||||||
websocket_port: 53511
|
websocket_port: 53511
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export interface Log {
|
export interface Log {
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
level: 'info' | 'warning' | 'error' | 'debug';
|
level: 'info' | 'warning' | 'error' | 'debug' | 'progress';
|
||||||
context: string;
|
context: string;
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,7 @@ export interface Settings {
|
|||||||
always_reencode_video: boolean;
|
always_reencode_video: boolean;
|
||||||
embed_video_metadata: boolean;
|
embed_video_metadata: boolean;
|
||||||
embed_audio_metadata: boolean;
|
embed_audio_metadata: boolean;
|
||||||
|
embed_video_thumbnail: boolean;
|
||||||
embed_audio_thumbnail: boolean;
|
embed_audio_thumbnail: boolean;
|
||||||
use_cookies: boolean;
|
use_cookies: boolean;
|
||||||
import_cookies_from: string;
|
import_cookies_from: string;
|
||||||
@@ -44,6 +45,13 @@ export interface Settings {
|
|||||||
use_custom_commands: boolean;
|
use_custom_commands: boolean;
|
||||||
custom_commands: CustomCommand[];
|
custom_commands: CustomCommand[];
|
||||||
filename_template: string;
|
filename_template: string;
|
||||||
|
debug_mode: boolean;
|
||||||
|
log_verbose: boolean;
|
||||||
|
log_warning: boolean;
|
||||||
|
log_progress: boolean;
|
||||||
|
enable_notifications: boolean;
|
||||||
|
update_notification: boolean;
|
||||||
|
download_completion_notification: boolean;
|
||||||
// extension settings
|
// extension settings
|
||||||
websocket_port: number;
|
websocket_port: number;
|
||||||
}
|
}
|
||||||
@@ -52,5 +60,6 @@ export interface DownloadConfiguration {
|
|||||||
output_format: string | null;
|
output_format: string | null;
|
||||||
embed_metadata: boolean | null;
|
embed_metadata: boolean | null;
|
||||||
embed_thumbnail: boolean | null;
|
embed_thumbnail: boolean | null;
|
||||||
|
sponsorblock: string | null;
|
||||||
custom_command: string | null;
|
custom_command: string | null;
|
||||||
}
|
}
|
||||||
|
|||||||