From 8b580a4ce5052637ab66f6cc0412a4c5adb4918d Mon Sep 17 00:00:00 2001 From: Aswanidev Date: Thu, 5 Mar 2026 18:36:04 +0530 Subject: [PATCH 1/9] fix the new issue for the codec of webm and mp4 and m4a --- app.go | 157 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 119 insertions(+), 38 deletions(-) diff --git a/app.go b/app.go index acf0d9b..0ed011a 100644 --- a/app.go +++ b/app.go @@ -412,78 +412,159 @@ func extractResolution(resolution string) string { /* -------------------- Format Builders -------------------- */ +// buildVideoFormatString builds format string for mp4 container with proper codec handling +// Uses separate video+audio selection to ensure reliable merging func buildVideoFormatString(cleanRes string, preferH264 bool) string { - // Build format string that handles all codecs (h264, vp9, av1) - // CRITICAL: Always use m4a audio for mp4 container compatibility - // webm/opus audio causes ffmpeg merge failures with mp4 video + // Build format string that prioritizes h264+aac for mp4 container compatibility + // Use separate selection (bv*+ba*) to ensure proper download and merging if cleanRes == "best" { - // Try h264 first, then vp9, then av1 - // Audio: STRICTLY m4a/aac only to ensure mp4 compatibility - return "bestvideo[vcodec^=avc1]+bestaudio[ext=m4a]/" + - "bestvideo[vcodec^=avc1]+bestaudio[acodec^=mp4a]/" + - "bestvideo[vcodec^=vp9]+bestaudio[ext=m4a]/" + - "bestvideo[vcodec^=vp9]+bestaudio[acodec^=mp4a]/" + - "bestvideo[vcodec^=av01]+bestaudio[ext=m4a]/" + - "bestvideo[vcodec^=av01]+bestaudio[acodec^=mp4a]/" + - "bestvideo+bestaudio[ext=m4a]/" + - "bestvideo+bestaudio[acodec^=mp4a]/" + - "bestvideo+bestaudio/best" + // Best quality - prioritize h264 with aac/m4a for reliable mp4 merging + return "bestvideo[vcodec^=avc1]+bestaudio[ext=m4a]/bestvideo[vcodec^=avc1]+bestaudio[acodec^=mp4a]/" + + "bestvideo[vcodec^=avc1]+bestaudio/" + + "bestvideo[vcodec^=vp9]+bestaudio[ext=m4a]/bestvideo[vcodec^=vp9]+bestaudio[acodec^=mp4a]/" + + "bestvideo[vcodec^=vp9]+bestaudio/" + + "bestvideo[vcodec^=av01]+bestaudio[ext=m4a]/bestvideo[vcodec^=av01]+bestaudio[acodec^=mp4a]/" + + "bestvideo[vcodec^=av01]+bestaudio/" + + "bestvideo+bestaudio[ext=m4a]/bestvideo+bestaudio[acodec^=mp4a]/bestvideo+bestaudio/best" } resNum, _ := strconv.Atoi(cleanRes) if resNum >= 1440 { - // High resolutions - try exact height first, then fall back to <= - // STRICTLY m4a audio only to prevent ffmpeg merge failures + // High resolutions (1440p+) - prioritize h264 with exact or close height match return fmt.Sprintf( - // Try exact height match first with m4a audio only + // h264 with m4a audio - best for mp4 merging "bestvideo[vcodec^=avc1][height=%s]+bestaudio[ext=m4a]/"+ "bestvideo[vcodec^=avc1][height=%s]+bestaudio[acodec^=mp4a]/"+ + "bestvideo[vcodec^=avc1][height=%s]+bestaudio/"+ + // h264 with <= height fallback + "bestvideo[vcodec^=avc1][height<=%s]+bestaudio[ext=m4a]/"+ + "bestvideo[vcodec^=avc1][height<=%s]+bestaudio[acodec^=mp4a]/"+ + "bestvideo[vcodec^=avc1][height<=%s]+bestaudio/"+ + // vp9 fallback "bestvideo[vcodec^=vp9][height=%s]+bestaudio[ext=m4a]/"+ "bestvideo[vcodec^=vp9][height=%s]+bestaudio[acodec^=mp4a]/"+ + "bestvideo[vcodec^=vp9][height=%s]+bestaudio/"+ + // av1 fallback "bestvideo[vcodec^=av01][height=%s]+bestaudio[ext=m4a]/"+ "bestvideo[vcodec^=av01][height=%s]+bestaudio[acodec^=mp4a]/"+ - // Fall back to <= if exact match not available - still m4a only - "bestvideo[vcodec^=avc1][height<=%s]+bestaudio[ext=m4a]/"+ - "bestvideo[vcodec^=avc1][height<=%s]+bestaudio[acodec^=mp4a]/"+ - "bestvideo[vcodec^=vp9][height<=%s]+bestaudio[ext=m4a]/"+ - "bestvideo[vcodec^=vp9][height<=%s]+bestaudio[acodec^=mp4a]/"+ - "bestvideo[vcodec^=av01][height<=%s]+bestaudio[ext=m4a]/"+ - "bestvideo[vcodec^=av01][height<=%s]+bestaudio[acodec^=mp4a]/"+ - // Final fallbacks - still prefer m4a + "bestvideo[vcodec^=av01][height=%s]+bestaudio/"+ + // Any video codec fallback "bestvideo[height<=%s]+bestaudio[ext=m4a]/"+ "bestvideo[height<=%s]+bestaudio[acodec^=mp4a]/"+ + "bestvideo[height<=%s]+bestaudio/"+ "best[height<=%s]", cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, - cleanRes, cleanRes, cleanRes, + cleanRes, cleanRes, cleanRes, cleanRes, ) } - // Standard resolutions - try exact height first, then fall back - // STRICTLY m4a audio only to prevent ffmpeg merge failures + // Standard resolutions - prioritize h264 with m4a audio return fmt.Sprintf( - // Try exact height match first with m4a audio only + // h264 with m4a audio - best for mp4 merging "bestvideo[vcodec^=avc1][height=%s]+bestaudio[ext=m4a]/"+ "bestvideo[vcodec^=avc1][height=%s]+bestaudio[acodec^=mp4a]/"+ + "bestvideo[vcodec^=avc1][height=%s]+bestaudio/"+ + // h264 with <= height fallback + "bestvideo[vcodec^=avc1][height<=%s]+bestaudio[ext=m4a]/"+ + "bestvideo[vcodec^=avc1][height<=%s]+bestaudio[acodec^=mp4a]/"+ + "bestvideo[vcodec^=avc1][height<=%s]+bestaudio/"+ + // vp9 fallback "bestvideo[vcodec^=vp9][height=%s]+bestaudio[ext=m4a]/"+ "bestvideo[vcodec^=vp9][height=%s]+bestaudio[acodec^=mp4a]/"+ + "bestvideo[vcodec^=vp9][height=%s]+bestaudio/"+ + // av1 fallback "bestvideo[vcodec^=av01][height=%s]+bestaudio[ext=m4a]/"+ "bestvideo[vcodec^=av01][height=%s]+bestaudio[acodec^=mp4a]/"+ - // Fall back to <= if exact match not available - still m4a only - "bestvideo[vcodec^=avc1][height<=%s]+bestaudio[ext=m4a]/"+ - "bestvideo[vcodec^=avc1][height<=%s]+bestaudio[acodec^=mp4a]/"+ - "bestvideo[vcodec^=vp9][height<=%s]+bestaudio[ext=m4a]/"+ - "bestvideo[vcodec^=vp9][height<=%s]+bestaudio[acodec^=mp4a]/"+ - "bestvideo[vcodec^=av01][height<=%s]+bestaudio[ext=m4a]/"+ - "bestvideo[vcodec^=av01][height<=%s]+bestaudio[acodec^=mp4a]/"+ - // Final fallbacks - still prefer m4a + "bestvideo[vcodec^=av01][height=%s]+bestaudio/"+ + // Any video codec fallback "bestvideo[height<=%s]+bestaudio[ext=m4a]/"+ "bestvideo[height<=%s]+bestaudio[acodec^=mp4a]/"+ + "bestvideo[height<=%s]+bestaudio/"+ + "best[height<=%s]", + cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, + cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, + cleanRes, cleanRes, cleanRes, cleanRes, + ) +} + +// buildWebmFormatString builds format string for webm container with VP9/AV1 + opus +// This ensures best quality webm output with modern codecs +func buildWebmFormatString(cleanRes string) string { + // For webm, we want VP9 or AV1 video with opus audio + // This provides better quality than older vp8/opus combinations + + if cleanRes == "best" { + // Best quality webm - prioritize av01 (AV1) then vp9 + return "bestvideo[vcodec^=av01]+bestaudio[acodec^=opus]/" + + "bestvideo[vcodec^=av01]+bestaudio[ext=webm]/" + + "bestvideo[vcodec^=av01]+bestaudio/" + + "bestvideo[vcodec^=vp9]+bestaudio[acodec^=opus]/" + + "bestvideo[vcodec^=vp9]+bestaudio[ext=webm]/" + + "bestvideo[vcodec^=vp9]+bestaudio/" + + "bestvideo[vcodec^=vp8]+bestaudio[acodec^=opus]/" + + "bestvideo[vcodec^=vp8]+bestaudio/" + + "bestvideo+bestaudio[acodec^=opus]/bestvideo+bestaudio/best" + } + + resNum, _ := strconv.Atoi(cleanRes) + if resNum >= 1440 { + // High resolutions - prioritize av01 then vp9 + return fmt.Sprintf( + // AV1 with opus - best quality + "bestvideo[vcodec^=av01][height=%s]+bestaudio[acodec^=opus]/"+ + "bestvideo[vcodec^=av01][height=%s]+bestaudio[ext=webm]/"+ + "bestvideo[vcodec^=av01][height=%s]+bestaudio/"+ + // AV1 <= height fallback + "bestvideo[vcodec^=av01][height<=%s]+bestaudio[acodec^=opus]/"+ + "bestvideo[vcodec^=av01][height<=%s]+bestaudio[ext=webm]/"+ + "bestvideo[vcodec^=av01][height<=%s]+bestaudio/"+ + // VP9 with opus + "bestvideo[vcodec^=vp9][height=%s]+bestaudio[acodec^=opus]/"+ + "bestvideo[vcodec^=vp9][height=%s]+bestaudio[ext=webm]/"+ + "bestvideo[vcodec^=vp9][height=%s]+bestaudio/"+ + // VP9 <= height fallback + "bestvideo[vcodec^=vp9][height<=%s]+bestaudio[acodec^=opus]/"+ + "bestvideo[vcodec^=vp9][height<=%s]+bestaudio[ext=webm]/"+ + "bestvideo[vcodec^=vp9][height<=%s]+bestaudio/"+ + // Any codec fallback + "bestvideo[height<=%s]+bestaudio[acodec^=opus]/"+ + "bestvideo[height<=%s]+bestaudio[ext=webm]/"+ + "bestvideo[height<=%s]+bestaudio/"+ + "best[height<=%s]", + cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, + cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, + cleanRes, cleanRes, cleanRes, cleanRes, + ) + } + + // Standard resolutions - prioritize av01 then vp9 with opus + return fmt.Sprintf( + // AV1 with opus + "bestvideo[vcodec^=av01][height=%s]+bestaudio[acodec^=opus]/"+ + "bestvideo[vcodec^=av01][height=%s]+bestaudio[ext=webm]/"+ + "bestvideo[vcodec^=av01][height=%s]+bestaudio/"+ + // AV1 <= height fallback + "bestvideo[vcodec^=av01][height<=%s]+bestaudio[acodec^=opus]/"+ + "bestvideo[vcodec^=av01][height<=%s]+bestaudio[ext=webm]/"+ + "bestvideo[vcodec^=av01][height<=%s]+bestaudio/"+ + // VP9 with opus + "bestvideo[vcodec^=vp9][height=%s]+bestaudio[acodec^=opus]/"+ + "bestvideo[vcodec^=vp9][height=%s]+bestaudio[ext=webm]/"+ + "bestvideo[vcodec^=vp9][height=%s]+bestaudio/"+ + // VP9 <= height fallback + "bestvideo[vcodec^=vp9][height<=%s]+bestaudio[acodec^=opus]/"+ + "bestvideo[vcodec^=vp9][height<=%s]+bestaudio[ext=webm]/"+ + "bestvideo[vcodec^=vp9][height<=%s]+bestaudio/"+ + // Any codec fallback + "bestvideo[height<=%s]+bestaudio[acodec^=opus]/"+ + "bestvideo[height<=%s]+bestaudio[ext=webm]/"+ + "bestvideo[height<=%s]+bestaudio/"+ "best[height<=%s]", cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, cleanRes, - cleanRes, cleanRes, cleanRes, + cleanRes, cleanRes, cleanRes, cleanRes, ) } From dcc58e848e46b366a7f6ff4fdebf60856da70ef3 Mon Sep 17 00:00:00 2001 From: Aswanidev Date: Thu, 5 Mar 2026 19:37:39 +0530 Subject: [PATCH 2/9] improve readme.md --- README.md | 155 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 120 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 743e906..acf8878 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,88 @@ # Predator

- +

-A simple desktop app for grabbing videos and audio from YouTube and Instagram. Built with Go and Wails (web tech frontend), using yt-dlp under the hood to do the heavy lifting. - -## What it does +

+Stars +Release +Downloads +License +

-- **Download videos** from YouTube in any resolution from 144p up to 4K -- **Grab audio only** in MP3, M4A, Opus, or WAV format -- **Works with Instagram too** - reels, posts, stories, TV videos -- **Playlist support** - Download entire YouTube playlists or pick specific videos -- **Shows file sizes** before you download so you know what you're getting into -- **Live progress tracking** - Watch speed, ETA, and percentage in real-time -- **Cancel anytime** - Change your mind? Hit cancel and it stops cleanly -- **Picks up where it left off** - Failed downloads auto-retry up to 3 times -- **Duplicate detection** - Warns if you already downloaded something -- **Choose where files go** - Set your download folder once, it remembers -- **Keeps history** - See what you've downloaded, filter by video/audio, open files directly -- **Dark and light themes** - Toggle with Ctrl+T +A simple desktop app for grabbing videos and audio from YouTube and Instagram. Built with Go and Wails (web tech frontend), using yt-dlp under the hood to do the heavy lifting. -## Getting started +## Table of Contents + +- [Features](#features) +- [Getting Started](#getting-started) +- [How to Use](#how-to-use) +- [Keyboard Shortcuts](#keyboard-shortcuts) +- [Technical Details](#technical-details) +- [Requirements](#requirements) +- [Troubleshooting](#troubleshooting) +- [Contributing](#contributing) +- [License](#license) + +## Features + +### Video Downloads +- **Multiple resolutions** - From 144p up to 4K (2160p) +- **Best quality option** - Automatically picks the highest available +- **Smart codec handling** - Uses H.264 video + AAC audio for maximum compatibility +- **WebM support** - Available with VP9/AV1 + Opus for better quality + +### Audio Downloads +- **Multiple formats** - MP3, M4A, Opus, or WAV +- **High quality output** - Uses best available source and converts to your chosen format +- **MP3**: V0 quality (~245kbps) +- **M4A**: AAC 192kbps +- **WAV**: 16-bit PCM 44.1kHz stereo + +### Platform Support +- **YouTube** - Videos, shorts, live streams +- **Instagram** - Reels, posts, stories, TV videos + +### User Experience +- **Playlist support** - Download entire playlists or select specific videos +- **File size preview** - See file sizes before downloading +- **Live progress** - Real-time speed, ETA, and percentage tracking +- **Cancel anytime** - Clean cancellation with automatic temp file cleanup +- **Auto-retry** - Failed downloads retry up to 3 times automatically +- **Duplicate detection** - Warns if content was already downloaded +- **Custom download folder** - Set once, remembers forever +- **Download history** - View past downloads, filter by type, open file location +- **Theme toggle** - Dark and light themes (Ctrl+T) + +## Getting Started You'll need **Go 1.24 or newer** installed. ```bash +# Clone the repository git clone https://github.com/Aswanidev-vs/Predator.git cd Predator + +# Install dependencies go mod download ``` -To run in development mode: +### Running the App +**Development mode:** ```bash wails dev ``` -To build the actual app: - +**Build for production:** ```bash wails build ``` **First time setup:** The app will ask to download yt-dlp and ffmpeg automatically. Just say yes - it handles everything and caches them locally. No need to install anything else manually. -## How to use +## How to Use 1. **Open the app** - It'll show the main download tab 2. **Set your download folder** - Click "Change Download Location" (or it'll use the current folder) @@ -55,31 +92,78 @@ wails build - For audio: Pick format (MP3, M4A, Opus, WAV) 5. **Hit download** - Watch the progress bar do its thing +## Keyboard Shortcuts + +| Shortcut | Action | +|----------|--------| +| `Ctrl+L` | Focus the URL input | +| `Ctrl+D` | Start download (when button is active) | +| `Ctrl+T` | Toggle dark/light theme | +| `Esc` | Close any open modal | + **Pro tips:** -- **Ctrl+L** - Focus the URL input -- **Ctrl+D** - Start download (when button is active) -- **Ctrl+T** - Toggle dark/light theme -- **Esc** - Close any open modal - Playlists show a modal where you can select specific videos to download - Click the folder icon in history to open where a file is saved +- The app auto-updates yt-dlp to the latest version on each download + +## Technical Details + +### Video Format +- **Container:** MP4 (with WebM option) +- **Video codec:** H.264 (avc1) for maximum device compatibility +- **Audio codec:** AAC (m4a) for best audio quality +- **Fallback handling:** If preferred codec isn't available, automatically falls back to next best option -## A few things to know +### Audio Format +- Uses best available source (webm/opus or m4a/aac) and converts to your chosen format using ffmpeg -- **Resolutions:** The app tries to get exactly what you picked. If that's not available, it falls back to the next best quality automatically. -- **Video format:** Everything gets merged into a single MP4 file with H.264 codec for maximum compatibility. -- **Audio quality:** Uses the best available source and converts to your chosen format. -- **Downloads folder:** Set via the button or environment variable `PREDATOR_OUTPUT_DIR`. -- **History:** Stored locally in `~/.predator/history.json` (keeps last 100 items). -- **Concurrent downloads:** Max 3 at a time to not overwhelm your connection. -- **Partial files:** If you cancel, the app cleans up `.part` and temp files automatically. +### File Locations +- **Downloads:** User-selected folder or `PREDATOR_OUTPUT_DIR` environment variable +- **History:** `~/.predator/history.json` (keeps last 100 items) +- **Settings:** `~/.predator/settings.json` +- **Dependencies:** `~/.cache/yt-dlp/` (yt-dlp, ffmpeg, ffprobe) + +### Performance +- **Concurrent downloads:** Max 3 at a time to not overwhelm your connection +- **Progress updates:** Every 200ms for smooth progress bars +- **Speed smoothing:** Uses exponential moving average for stable speed display + +### Cleanup +- Cancelled downloads automatically clean up `.part` and temp files +- Failed downloads after max retries also trigger cleanup ## Requirements - Go 1.24+ -- Internet connection (obviously) +- Internet connection - yt-dlp and ffmpeg (auto-installed on first run) -## Legal stuff +## Troubleshooting + +### "ffmpeg not found" error +The app will prompt you to download ffmpeg on first run. If you skip it, you can: +1. Install ffmpeg manually from [ffmpeg.org](https://ffmpeg.org) +2. Or delete `~/.cache/yt-dlp/` and restart the app - it'll ask again + +### Slow downloads +- Check your internet connection +- YouTube might be throttling (try a different resolution) +- Max 3 concurrent downloads - close other apps using bandwidth + +### Download fails with "format not available" +- Try a lower resolution +- The video might be region-locked or unavailable +- Try using "best" option for auto-selection of best available + +### "Permission denied" errors +- Check if your download folder is writable +- Try a different download location + +## Contributing + +Contributions are welcome! Please read the [CONTRIBUTING.md](CONTRIBUTING.md) file for guidelines. + +## Legal Stuff **This tool is for educational and personal use only.** @@ -97,3 +181,4 @@ MIT License - see [LICENSE](LICENSE) file. --- Built with [Wails](https://wails.io/) + Go + vanilla JS. No React, no bloat. + From 7cc915de5d2fafee6debd9bfc4f529c51cbca6f1 Mon Sep 17 00:00:00 2001 From: Aswanidev Date: Thu, 5 Mar 2026 19:39:13 +0530 Subject: [PATCH 3/9] improve readme.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index acf8878..f999f78 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,8 @@

-Stars + Release -Downloads -License

A simple desktop app for grabbing videos and audio from YouTube and Instagram. Built with Go and Wails (web tech frontend), using yt-dlp under the hood to do the heavy lifting. From d9e21326d38cab0121a5043e45d800f0520d4116 Mon Sep 17 00:00:00 2001 From: Aswanidev Date: Thu, 5 Mar 2026 19:44:49 +0530 Subject: [PATCH 4/9] backup --- .github/workflows/submodule-check.yml | 62 +++++++++++++++++++++++++++ CONTRIBUTING.md | 24 +++++++++++ 2 files changed, 86 insertions(+) create mode 100644 .github/workflows/submodule-check.yml create mode 100644 CONTRIBUTING.md diff --git a/.github/workflows/submodule-check.yml b/.github/workflows/submodule-check.yml new file mode 100644 index 0000000..4acbe7d --- /dev/null +++ b/.github/workflows/submodule-check.yml @@ -0,0 +1,62 @@ +name: Submodule Cleanliness Check + +on: + pull_request: + branches: [ main, master ] + push: + branches: [ main, master ] + +jobs: + verify-submodules: + runs-on: ubuntu-latest + steps: + - name: Checkout repository with submodules + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: Initialize/Update submodules + run: | + git submodule sync --recursive + git submodule update --init --recursive --jobs 4 + + - name: Ensure submodule status has no anomalies + run: | + set -euo pipefail + anomalies=0 + + echo "Checking git submodule status output" + status_output=$(git submodule status --recursive || true) + echo "$status_output" + + # If any line starts with '-', submodule is not initialized + if echo "$status_output" | grep -E '^-' >/dev/null; then + echo "ERROR: Found uninitialized submodules (lines starting with '-')" >&2 + anomalies=1 + fi + + # If any line starts with '+', submodule commit is different than recorded + if echo "$status_output" | grep -E '^\+' >/dev/null; then + echo "ERROR: Found submodules not at recorded commit (lines starting with '+')" >&2 + anomalies=1 + fi + + # If any line contains 'dirty', submodule has local changes + if echo "$status_output" | grep -E 'dirty' >/dev/null; then + echo "ERROR: Found dirty submodule working trees" >&2 + anomalies=1 + fi + + # Also ensure working tree under submodules is clean + if ! git diff --submodule=diff --quiet; then + echo "ERROR: Detected differences in submodules (working tree not clean)" >&2 + anomalies=1 + fi + + if [ "$anomalies" -ne 0 ]; then + echo "Submodule anomalies detected; failing the job." >&2 + exit 1 + fi + + echo "Submodule status clean." diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..bd6cab8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,24 @@ +# Contributing + +## Submodules policy + +This repository includes a `frontend/` submodule. To maintain reproducible builds and CI integrity: + +- Never commit a dirty submodule state. Ensure `git submodule status` shows no `dirty` markers. +- Update submodules deterministically using: + - `git submodule sync --recursive` + - `git submodule update --init --recursive --checkout` +- When you change the `frontend/` code, commit and push inside the submodule first, then update the pointer in this repo: + 1. `cd frontend` + 2. Work and commit: `git add -A && git commit -m "feat: ..." && git push` + 3. `cd .. && git add frontend && git commit -m "chore(frontend): bump submodule" && git push` + +CI will block merges that contain uninitialized, mismatched, or dirty submodule pointers (see `.github/workflows/submodule-check.yml`). + +## Development quickstart + +- Clone with submodules: `git clone --recurse-submodules https://github.com/Aswanidev-vs/Predator.git` +- Or initialize after clone: `git submodule update --init --recursive` +- Go toolchain: see `go.mod` (`go 1.25`). Build/dev commands: + - Dev: `wails dev` + - Build: `wails build` From f7e2b029f567c784400c02a28b3a00d6db6937ab Mon Sep 17 00:00:00 2001 From: Aswanidev vs Date: Thu, 5 Mar 2026 20:17:59 +0530 Subject: [PATCH 5/9] Update README.md --- README.md | 86 +++++++++++++------------------------------------------ 1 file changed, 20 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index fd9fb8d..f999f78 100644 --- a/README.md +++ b/README.md @@ -70,27 +70,25 @@ go mod download **Development mode:** ```bash -go run main.go +wails dev ``` **Build for production:** ```bash -# For Windows -go install fyne.io/tools/cmd/fyne-cross@latest -fyne-cross windows - -# For macOS -fyne-cross darwin - -# For Linux -fyne-cross linux +wails build ``` -## Usage +**First time setup:** The app will ask to download yt-dlp and ffmpeg automatically. Just say yes - it handles everything and caches them locally. No need to install anything else manually. ## How to Use -## Architecture +1. **Open the app** - It'll show the main download tab +2. **Set your download folder** - Click "Change Download Location" (or it'll use the current folder) +3. **Paste a URL** - YouTube or Instagram links both work +4. **Pick your format:** + - For video: Choose resolution (144p to 4K, or "best") + - For audio: Pick format (MP3, M4A, Opus, WAV) +5. **Hit download** - Watch the progress bar do its thing ## Keyboard Shortcuts @@ -132,41 +130,7 @@ fyne-cross linux - Cancelled downloads automatically clean up `.part` and temp files - Failed downloads after max retries also trigger cleanup -- `main()`: Initializes the UI and event handlers -- `fetchVideoInfo()`: Dynamically fetches video metadata and available resolutions -- `formatBytes()`: Converts byte sizes to human-readable format -- `formatETA()`: Converts duration to HH:MM:SS format - -## Project Structure - -``` -Predator/ -├── main.go # Main application code -├── go.mod # Go module definition -├── go.sum # Go module checksums -├── logov4.png # Application icon -├── asset/ # Icon and logo assets -├── fyne-cross/ # Cross-platform build configuration -├── sample.txt # Code sample reference -└── samplev*.txt # Additional code samples -``` - -## Dependencies - -- **fyne.io/fyne/v2**: Cross-platform GUI framework -- **github.com/lrstanley/go-ytdlp**: Go wrapper for yt-dlp - - -## Performance - -- **Lazy Metadata Loading**: Video info is only fetched when a valid URL is entered -- **Debounced Input**: 600ms debounce on URL input to prevent excessive API calls -- **Atomic Operations**: Thread-safe state management for concurrent operations -- **Streaming Download**: Supports live progress updates during download - -## Disclaimer - -**IMPORTANT LEGAL NOTICE** +## Requirements - Go 1.24+ - Internet connection @@ -199,30 +163,20 @@ Contributions are welcome! Please read the [CONTRIBUTING.md](CONTRIBUTING.md) fi ## Legal Stuff -- **Copyright Compliance**: Users must respect copyright laws and YouTube's Terms of Service. Downloading copyrighted content without proper authorization may be illegal in your jurisdiction. -- **Terms of Service**: By using this application, you acknowledge that you are bound by YouTube's Terms of Service and agree not to violate them. -- **Personal Use Only**: This tool is intended for downloading content you own or have permission to download. -- **Liability**: The authors and contributors of Predator are not responsible for: - - Any copyright infringement or violations of third-party rights - - Misuse of downloaded content - - Any legal consequences arising from use of this application - - Data loss or corruption - - Any other damages resulting from use of this software +**This tool is for educational and personal use only.** -### Responsible Use +- Respect copyright laws and YouTube's Terms of Service +- Only download content you own or have permission to download +- Don't use this to redistribute copyrighted material +- The authors aren't responsible for how you use this tool -Users should: -- Only download content they have permission to download -- Respect content creators' rights and intellectual property -- Use downloaded content in compliance with local laws -- Not distribute copyrighted content without proper licensing -- Be aware that many YouTube videos are protected by copyright +Basically: be cool, don't pirate stuff you shouldn't. -### No Warranty +## License -This application is provided "as-is" without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, or non-infringement. +MIT License - see [LICENSE](LICENSE) file. -The authors assume no responsibility for any illegal activities or misuse of this tool. By using Predator, you accept all risks and responsibilities associated with your downloads. +--- Built with [Wails](https://wails.io/) + Go + vanilla JS. No React, no bloat. From 30cbc5449dff6d22fbf6faa3f2883ae00018c0ec Mon Sep 17 00:00:00 2001 From: Aswanidev Date: Thu, 5 Mar 2026 23:50:56 +0530 Subject: [PATCH 6/9] fix the playlist issue and related issues --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f38c484..61caa98 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build/bin TODO.md +node_modules/ \ No newline at end of file From a3e8e708316fee97aca5fafcb1b6fc42b0821c93 Mon Sep 17 00:00:00 2001 From: Aswanidev Date: Fri, 6 Mar 2026 17:59:41 +0530 Subject: [PATCH 7/9] backup code --- .gitignore | 3 ++- README.md | 10 +--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 61caa98..b00c9e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/bin TODO.md -node_modules/ \ No newline at end of file +node_modules/ + diff --git a/README.md b/README.md index f999f78..9ab3fd7 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ A simple desktop app for grabbing videos and audio from YouTube and Instagram. B - **Duplicate detection** - Warns if content was already downloaded - **Custom download folder** - Set once, remembers forever - **Download history** - View past downloads, filter by type, open file location -- **Theme toggle** - Dark and light themes (Ctrl+T) + ## Getting Started @@ -90,14 +90,6 @@ wails build - For audio: Pick format (MP3, M4A, Opus, WAV) 5. **Hit download** - Watch the progress bar do its thing -## Keyboard Shortcuts - -| Shortcut | Action | -|----------|--------| -| `Ctrl+L` | Focus the URL input | -| `Ctrl+D` | Start download (when button is active) | -| `Ctrl+T` | Toggle dark/light theme | -| `Esc` | Close any open modal | **Pro tips:** - Playlists show a modal where you can select specific videos to download From f7f06e1a227122b02d49d9f5abbeb18f089836e2 Mon Sep 17 00:00:00 2001 From: Aswanidev Date: Fri, 6 Mar 2026 18:05:36 +0530 Subject: [PATCH 8/9] ignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index b00c9e3..214c86a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ build/bin - TODO.md node_modules/ From 07ec0f84905be4059fd8896808df90db95349bfd Mon Sep 17 00:00:00 2001 From: Aswanidev Date: Sat, 14 Mar 2026 19:24:17 +0530 Subject: [PATCH 9/9] backup --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index b00c9e3..214c86a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ build/bin - TODO.md node_modules/