Open-source desktop video downloader powered by yt-dlp. Paste a URL, pick a quality, download.
Supports YouTube, Vimeo, Twitter/X, SoundCloud, Instagram, and thousands of other sites.
Everything runs locally on your machine - no cloud, no accounts, no tracking.
Go to the Releases page, scroll down to Assets, and click the file for your system:
- macOS:
ArcDLP-x.x.x.dmg - Windows:
ArcDLP-Setup-x.x.x.exe - Linux:
ArcDLP-x.x.x.AppImage
No dependencies to install. yt-dlp and ffmpeg are bundled inside the app.
- Download the
.dmgfile - Open it and drag ArcDLP to your Applications folder
- Open ArcDLP
macOS will show a security warning the first time because the app is not code-signed yet. This is normal.
To fix it:
- Click Done
- Open System Settings
- Go to Privacy & Security
- Scroll down and click Open Anyway next to ArcDLP
- Enter your password
You only need to do this once.
- Download and run the
.exeinstaller - Click More info, then click Run anyway
- The installer will set up ArcDLP and create a shortcut automatically
ArcDLP installs per-user (no admin required) and can be uninstalled from Settings > Apps.
- Download the
.AppImagefile - Make it executable: right-click → Properties → Permissions → check Allow executing file as program
- Double-click to run
- Single video downloads - Fetch video info, preview metadata, choose quality (4K/2K/1080p/720p/480p/360p/240p), and download as MP4 or extract audio as MP3
- Playlist support - Paste a playlist URL, select which items to download, pick a format, and queue them all at once
- Instagram saved collections - Paste a saved collection URL, the app scrapes all post links from the collection page, and queues them for download
- Download queue - Sequential processing with per-item progress, retry, cancel, and skip. One failure never stops the rest
- YouTube sign-in - Access age-restricted, private, and members-only content through a built-in browser login window. Credentials go directly to Google
- Instagram sign-in - Access your private saved collections through a built-in browser login window. Credentials go directly to Instagram
- Download history - Quick access to previously fetched videos with cached metadata
- Multi-site compatibility - Works with any site yt-dlp supports. Format detection adapts automatically to different streaming approaches across sites
- Update notifications - The app checks for new releases on startup and lets you know when an update is available
- Light and dark mode - Follows your system preference. macOS vibrancy supported
- Paste a video or playlist URL and click Fetch
- Pick a quality (or choose MP3 for audio extraction)
- Click Add to Queue
- Downloads are saved to
~/Downloads/ArcDLPby default (changeable in Settings)
For playlists, you can select/deselect individual items and choose a format for the whole batch before queueing.
To access private or age-restricted YouTube videos, sign in via Settings > YouTube Account. Your credentials go directly to Google through their standard login page.
yt-dlp supports downloading individual Instagram posts and reels, but it has no extractor for saved collections. ArcDLP bridges this gap with a built-in scraper.
- Sign in to Instagram via Settings > Instagram Account
- Paste a saved collection URL (e.g.
https://www.instagram.com/username/saved/collection-name/12345/) - Click Fetch - the app opens the collection page in a hidden browser window using your Instagram session
- It scrolls through the page, collecting all
<a>tags with/p/and/reel/href patterns - Found posts appear in a playlist-style picker where you can select/deselect items
- Click Add Selected to Queue - each post is downloaded individually via yt-dlp with your Instagram cookies
The scraper stops after 5 consecutive scrolls with no new posts, or after a 3-minute timeout (partial results are returned if any were found). Large collections may be rate-limited by Instagram.
If ArcDLP is useful to you, consider supporting development:
Everything below is for people who want to build from source, modify the app, or contribute.
Contributions are welcome. The codebase is intentionally simple - no frameworks, no build tools, vanilla JS throughout.
Before making changes, read through the code and match existing patterns. A few principles the project follows:
- Keep it simple. If something can be done in 30 lines, don't use a library.
- Resilience first. One failure should never kill the queue. Users should always know what's happening.
- Explicit actions only. No auto-fetching, no auto-retrying. Every action traces to a button click.
- Let yt-dlp do the work. Don't reimplement what yt-dlp already handles. The app is a GUI wrapper, not a competing tool.
- Multi-site compatibility. Never assume YouTube-specific behavior unless explicitly scoped. Format detection, error handling, and UI labels should work for any site yt-dlp supports.
- Fork and clone the repo
npm install(downloads yt-dlp + ffmpeg automatically) - See details below for Windows and Linux installnpm run devto launch with DevTools - See more details below- Make your changes, test across a few different sites
- Open a PR with a clear description of what changed and why
git clone https://github.com/archisvaze/arcdlp.git
cd arcdlp
npm installBoth ffmpeg-static and the yt-dlp postinstall script download platform-specific
binaries during npm install. On macOS, this works automatically, no setup needed.
If you're building for a different architecture (e.g. building the Linux x64
AppImage from an ARM machine), set these environment variables before
npm install to ensure the correct binaries are downloaded:
Windows (x64):
$env:npm_config_platform = "win32"
$env:npm_config_arch = "x64"
rm -r -Force node_modules
npm install
Linux (x64):
export npm_config_platform=linux
export npm_config_arch=x64
rm -rf node_modules bin
npm install
Only one binary per platform is downloaded per install. If you need to switch
target architectures, delete node_modules and bin and run npm install
again with the new env vars.
npm run dev # macOS / Linux
npm run dev:win # WindowsThis launches the app with DevTools enabled and verbose logging.
npm run build:mac # macOS - produces .dmg and .zip
npm run build:win # Windows - produces NSIS installer
npm run build:linux # Linux - produces AppImage
npm run build:all # All platformsBoth yt-dlp and ffmpeg binaries are bundled into the built app via
extraResources in package.json.
arcdlp/
├── src/
│ ├── main/
│ │ ├── main.js # Electron main process, IPC, window, history
│ │ ├── preload.js # Context bridge (window.api)
│ │ ├── ytdlp.js # yt-dlp integration: spawn, parse, download
│ │ ├── queue.js # Sequential download queue with per-item state
│ │ ├── cookies.js # YouTube + Instagram cookie auth
│ │ ├── scraper.js # Instagram collection scraper (BrowserWindow)
│ │ ├── updater.js # Update checker via GitHub Releases API
│ │ └── utils.js # Dev mode flag, logging helpers
│ └── renderer/
│ ├── index.html # UI structure
│ ├── renderer.js # UI logic, state, rendering
│ └── index.css # All styles
├── scripts/
│ ├── postinstall.js # Downloads yt-dlp binary on npm install
│ └── fix-ffmpeg-win.js # Renames ffmpeg for Windows builds
├── bin/ # yt-dlp binary (auto-populated by postinstall)
├── build/ # App icons (icon.icns, icon.ico, icon.png)
├── package.json
├── LICENSE
└── README.md
- User pastes a URL and clicks Fetch
- App spawns
yt-dlp --dump-jsonto get video metadata and available formats - User picks a quality preset or audio extraction
- Click "Add to Queue" - the download is queued and processed sequentially
- yt-dlp handles the actual download with
--progress-templatefor structured progress output - Completed files are saved to the configured download folder
For playlists, the app uses --flat-playlist --dump-json to stream items one at
a time, then queues selected items for download.
For Instagram saved collections, the app opens the collection page in a hidden
BrowserWindow, scrolls through it collecting anchor tags (<a href="/p/...">)
and (<a href="/reel/...">) via executeJavaScript, then presents the scraped
URLs in the playlist picker UI. Each post is then downloaded individually by
yt-dlp using the Instagram session cookies.
Only two runtime dependencies:
- electron-store - Persistent settings and history
- ffmpeg-static - Bundled ffmpeg binary for audio extraction and format merging
Dev dependencies: electron, electron-builder.
yt-dlp handles all downloading, format selection, and ffmpeg orchestration internally. The app is a GUI wrapper around it.
ArcDLP covers the core download workflow, but yt-dlp has a huge feature set that could be surfaced in the GUI. Here's what's planned and where contributors can help.
Thumbnails in playlist items - The data is already fetched, just not rendered yet(completed in v1.2.3)- File size estimates - Show approximate size on quality presets when available
- Download complete notification - System notification when the queue finishes (only if window is not focused)
- Playlist fetch cancellation - Currently can't cancel a playlist fetch mid-way through
- Verbose log toggle - Clean messages by default, raw yt-dlp output when debugging
yt-dlp supports a lot more than basic downloading. These features would make great contributions:
- Subtitle downloads -
--write-subs,--sub-langs, language selection UI - Embed metadata -
--embed-thumbnail,--embed-metadatafor tagging files - SponsorBlock integration -
--sponsorblock-remove,--sponsorblock-markto skip or mark sponsored segments - Additional audio formats - AAC, FLAC, WAV, Opus extraction (currently MP3 only)
- Format filtering - Expose yt-dlp's format selection syntax for advanced users
- Download archive -
--download-archiveto skip already-downloaded videos - Rate limiting -
--limit-ratefor bandwidth control - Proxy support -
--proxyfor users behind restrictive networks - Custom output templates -
--outputtemplate configuration in settings - Chapter splitting -
--split-chaptersto save individual chapters as separate files
- Keyboard shortcuts - Quick access to common actions
- More site-specific auth - Expand the cookie login flow to more sites beyond YouTube and Instagram
- Playlist detection for more sites - Currently conservative (YouTube, SoundCloud, and Instagram saved collections)
- DOM virtualization for large playlists - Currently renders all items, works fine under ~1000
video:fetchIPC returns the full raw JSON (50-200KB) even in production - should be dev-only- Queue
_itemsarray has no upper bound - consider a cap or auto-clear - Playlist checkbox uses inline
onchangehandler - could use event delegation - Log type detection is greedy (
msg.includes('complete')matches "incomplete")
- yt-dlp - The engine that does all the heavy lifting
- Electron - Desktop app framework
- ffmpeg - Audio/video processing (bundled via ffmpeg-static)
- electron-icon-builder - Made icon with Canva and exported the icon files via electron-icon-builder

