Paste a heap of links. Download them together.
A bulk download manager for 180+ sites, with a web UI and a command-line mode. Expand albums, folders and playlists into a queue, download files in parallel, and resume interrupted transfers. Runs on Linux, macOS, Windows and Docker; the web UI is built into the executable.
Download · Quick start · Documentation · Supported sites · Contribute · Get help
- Batch downloads: paste one link per line; supported albums, folders and playlists expand automatically.
- Resumable transfers: keep partial files, retry failures, and continue after an interruption.
- Control your bandwidth: adjust parallel downloads, connections per file and the native download speed limit while the queue runs.
- A queue you can navigate: search, filter, pause, retry individual files, and inspect logs from the browser. Light, dark and mobile layouts included.
- Desktop or automation: open the local web UI, pass URLs to the CLI, or run the Docker image on your server.
- One application: Go backend and embedded React UI. Releases include local CAPTCHA model data; Docker also includes the media helpers.
-
Open the latest release and choose the archive for your system:
System Archive ending Linux, Intel / AMD 64-bit linux_amd64.tar.gzLinux, ARM64 linux_arm64.tar.gzmacOS, Apple silicon darwin_arm64.tar.gzmacOS, Intel darwin_amd64.tar.gzWindows, Intel / AMD 64-bit windows_amd64.zip -
Extract the whole archive into a folder. Keep
ocr/beside the executable. No Go or Node.js installation is needed. -
Run
heapleach(heapleach.exeon Windows). It opens your browser and saves to your Downloads folder. -
Paste your links, one per line, and click Add to queue.
Terminal commands for Linux, macOS and Windows
Run these from a folder containing only the archive version you want to use.
# Linux x86-64; use linux_arm64 for an ARM64 machine.
tar -xzf heapleach_*_linux_amd64.tar.gz
./heapleach# macOS Apple silicon; use darwin_amd64 for an Intel Mac.
tar -xzf heapleach_*_darwin_arm64.tar.gz
./heapleach# Windows PowerShell
Expand-Archive -Path .\heapleach_*_windows_amd64.zip -DestinationPath .\heapleach
.\heapleach\heapleach.exeAn argument-free launch uses a free local port. After you close the browser, it exits once downloads are idle and no tab has connected for a minute. Unfinished jobs return held after a restart; click Resume to continue.
See installation and updates for checksums, Docker persistence, source builds and platform notes.
On Linux or macOS with Docker, run:
mkdir -p "$HOME/Downloads"
docker run --rm -it --name heapleach \
-p 127.0.0.1:8080:8080 \
--user "$(id -u):$(id -g)" \
-e HEAPLEACH_STATE=/downloads/.heapleach-state/queue.json.zst \
-v "$HOME/Downloads:/downloads" \
ghcr.io/johanlindvall/heapleach:latestOpen localhost:8080. Downloads and queue state stay
in your Downloads folder when the container stops. The image supports amd64
and arm64 and includes yt-dlp, ffmpeg, ffprobe, deno and local OCR. latest
follows successful main builds; use a versioned image
to pin a manual release.
The web UI has no login. The command above publishes it only on your computer; see network access for remote deployments.
# Open the UI on a free local port and choose the destination.
./heapleach -addr 127.0.0.1:0 -open ~/Downloads
# Download a list of URLs, then exit. Blank lines and # comments are ignored.
./heapleach - ~/Downloads < urls.txt
# Limit native download speed and parallel transfers.
./heapleach -addr 127.0.0.1:8080 -concurrency 4 -max-speed 10MB ~/Downloads
# Show every command-line option.
./heapleach -helpurls.txt contains your own URLs, one per line. On PowerShell, use
Get-Content .\urls.txt | .\heapleach.exe - to feed a list to the CLI.
To pass URLs directly, quote each one, especially links containing & or #.
The CLI exits 0 on success, 1 if any input or download fails, and 130
after Ctrl-C. Partial files remain available for resume. Native transfers
honor the shared speed limit; external helpers use their own controls.
Full usage guide · Configuration · Troubleshooting
File hosts, image galleries, video sites, broadcasters, image boards and compatible platforms are supported, including:
| Content | Examples |
|---|---|
| Files and folders | gofile, bunkr, MEGA, pixeldrain, MediaFire, Dropbox |
| Video and playlists | YouTube through yt-dlp, Vimeo, PeerTube |
| Broadcasts | SVT Play and other supported broadcasters |
| Galleries and collections | Chevereto, image boards, Internet Archive |
| Direct and embedded media | File URLs, HLS playlists (a DASH .mpd is refused with the reason), open directories, supported links embedded in webpages |
Some workflows need optional helpers. Support depends on what a host makes available; see accepted URL formats and limitations. Sites change, so fixture tests alone cannot guarantee current live support.
Expand the complete site inventory, generated from the extractor registry
98 extractors, each chosen by what a page serves rather than by its domain, so a site that moves, or an install nobody listed, is still recognised.
| Extractor | Recognises |
|---|---|
4chan |
4chan threads (/<board>/thread/<number>) whose page renders the thread's own t<number> container on the board and names the site |
abclisten |
episodes and programmes (/listen/programs/…) of ABC listen, by the page props its __NEXT_DATA__ island carries |
alohatube |
Aloha Tube view pages (/ktm/view.cgi?gid=<id>) that frame another site's player (an off-site <iframe allowfullscreen>), resolved where the video lives |
archive.org |
items (/details/<identifier>, /download/<identifier>[/<file>] and the other item routes) whose page is the archive's item page or file listing, or whose metadata API answers for the identifier |
ard |
videos (/video/…/<id>) and programmes (/sendung/, /serie/, /film/) of the ARD Mediathek, whose page loads from its page gateway |
arte |
programmes and collections (/<lang>/videos/<id>/, /embeds/<lang>/<id>) of ARTE, whose page calls its player API (/api/player/v2/) |
autoindex |
generated directory listings at any path: a page titled as an index of its own directory (Index of /…, Directory listing for /…) that links at least one entry inside it |
balbums |
searches of a Bunkr album index (/?search=<query>) whose page carries the index's search form, and its front page by that form and its "Page n of m" count, which is refused |
bandcamp |
releases (/album/<slug>, /track/<slug>), a band's /music and its front page, where the page is built from Bandcamp's client bundle and carries data-tralbum release data or the music grid |
bandzoogle |
pages of Bandzoogle band sites, at any path, whose player lists tracks as data-zoogle-track anchors |
bbcsounds |
episodes, brands and series (/sounds/play/<pid>, /sounds/brand/<pid>, /sounds/series/<pid>) served by the BBC Sounds web app |
bilibili |
videos (/video/BV<id>) and bangumi episodes whose page carries the bilibili player state (window.__INITIAL_STATE__ with its play information), short links included, and user spaces, series, lists and audio pages carrying its state or seed scripts |
bitchute |
videos and channels (/video/<id>/, /embed/<id>/, /channel/<id>/) served by the BitChute web app, a video naming its embed player |
booru |
image-board tag searches and posts on Danbooru, e621, Moebooru, Gelbooru, Philomena, Twibooru and szurubooru boards (/posts?tags=, /posts/<id>, /post/show/<id>, /index.php?page=post, /images/<id>, /post/<id>) whose page carries the software's markup and whose API answers for the same post or listing; Gelbooru 0.1 boards by their listing markup alone |
bunkr |
file pages (/f/<slug>, /v/<slug>, /i/<slug>) carrying a numeric data-file-id, and albums (/a/<slug>) listing theItem cards that link to file pages, or named Bunkr and linking file pages |
celeb |
creator galleries and images (/creator/<name>/images[/<id>], /creator/<name>) whose page is the site's Inertia app carrying the gallery's Creator/Media props in data-page |
chevereto |
Chevereto items, albums and user listings: pages below the site root carrying the platform's CHV.obj script namespace, or its generator or credit beside the item viewer, the data-object listing metadata or the password gate |
civitai |
images, posts, models and user galleries (/images/<id>, /posts/<id>, /models/<id>, /user/<name>) whose site's public API answers for that item on the page's own origin |
coomerfans |
creator pages (/u/<service>/<id>/<name>) listing that creator's /p/ posts, and posts (/p/<post>/<id>/<service>) carrying the post-body the media is read from |
cum |
creators and posts (/creators/<service>/<id>[/post/<post>]) whose page advertises its media servers as EDGE_BASE_URLS in the app's configuration |
cyberdrop |
albums (/a/<id>) listing #file entries with a file-size, and file pages (/f/<slug>, /e/<slug>) whose script asks the /api/file/info/ metadata endpoint |
dailymotion |
videos, playlists and user pages (/video/<xid>, /playlist/<xid>, /<user>) rendered by the Dailymotion server-side app (its neon bundle), short links included, and its embeddable player (/player/<id>.html?video=<xid>, the player id optional) |
direct |
anything else: a page's supported links or embedded player, or the URL as a plain file |
doodstream |
players (/e/<code>) naming the DoodStream /pass_md5/ token endpoint, landing pages (/d/<code>) naming DoodStream in their title or site metadata and framing its player, or either form showing its player gate, exact bare address refusal or removed-video page |
drive |
file links (/file/d/<id>, /open?id=, /uc?id=) whose page is the Google Drive file viewer (its apps-fileview bundle), the download confirmation form or Drive's quota or access refusal; folder links (/drive/folders/<id>) named Google Drive, which are refused |
dropbox |
share links (/s/…, /sh/…, /scl/fi/…, /scl/fo/…) whose page is the Dropbox viewer, loading its /static/atlas/ bundle |
drtuber |
watch pages and players (/video/<id>/<slug>, /embed/<id>) whose player is configured from the DrTuber player_config_json endpoint |
drtv |
programmes, seasons and series (/drtv/…/<slug>_<id>) of DR TV, served by its app with the state it boots from; audio pages (/lyd/…, /radio/…) served by the broadcaster's own front end are handed to yt-dlp |
emload |
file shares (/v2/file/<id>/<name>) whose page carries the dl-file download panel, or its removed-file or password notice |
eporner |
videos (/video-<id>/<slug>/, /hd-porn/<id>/) whose page sets the EPORNER player's video id and hash, and profile video tabs rendered with its profile script |
erome |
albums (/a/<id>) and profiles (/<user>) whose page carries the site's album markup (the album title heading and media group, or a profile's album links) |
fapello |
model pages and their posts (/<model>/, /<model>/<n>/) whose page links the model's own media under /content/…/<model>/ |
fediverse |
fediverse accounts, communities and posts (/@name, /users/<name>, /u/<name>, /c/<name>, /notes/<id>, /notice/<id>, /post/<n>, /p/<user>/<id>) on any server whose nodeinfo names its software |
feed |
RSS and Atom feeds, at any URL: a response served as a feed type, or whose document element is <rss> or <feed> |
filejump |
public shares (/s/<id>) whose page offers the share's own /s/<id>/download button |
filester |
file shares (/d/<slug>) loading file_dl.js beside a #downloadButton, and folders (/f/<id>) rendering their #filesGrid or #subfoldersGrid, listing file cards or asking for their password |
foolfuuka |
FoolFuuka archive threads, posts, searches and board pages (/<board>/thread/<n>/, /<board>/post/<n>/, /<board>/search/…, /<board>/) whose page names the software as its generator and loads its /foolfuuka/ assets, or whose origin's /_/api/chan/ answers the route with archived posts |
francetv |
video pages (/…/<id>-<slug>.html) and programme listings of France TV whose flight data names video_factory_ids; other .html pages of its app, such as a live channel's, are handed to yt-dlp |
gofile |
share links (/d/<code>, and the older /<code> and /?c=<code>) whose page is the Gofile app shell, loading its signing script |
goonbox |
GoonBox image viewers (/img/<id>, also /img/<slug>.<id>) served by its web app; original files are read from the public image metadata API |
hls |
bare HLS manifests: a response served as a playlist type or opening #EXTM3U, at any URL, or a .m3u8 link; .mpd links are taken in order to refuse them with the reason |
imagepond |
viewer pages (/i/<code>) naming their stored file (/media/…, /i/<code>/direct) in the player or og:video/og:image, and albums (/a/<code>) of cards linking to viewer pages, on pages named ImagePond |
imgur |
posts and albums (/a/<id>, /gallery/<slug>-<id>, /<id>) whose page carries window.postDataJSON or its own media as og:image, and account, tag and subreddit listings (/user/<name>, /t/<tag>, /r/<name>) whose listing JSON answers |
keep2share |
file links (/file/<id>) whose page is the Keep2Share or FileBoom web app shell (its entry-index bundle and chunk-client preload on #root), named Keep2Share or FileBoom; the name chooses the service's own API and proxy group |
kemono |
Kemono and Coomer creators and posts (/<service>/user/<id>, …/post/<id>) served by the sites' app shell, or whose origin's API returns the creator's matching profile |
knuthing |
watch pages (/watch/<video>.html) rendered by the KNUTHING theme, with or without their player, and its video listings (/videos/<section>) by their video list |
kvs |
Kernel Video Sharing pages — videos, member profiles, searches and listings — carrying the licensed player's configuration or script, the platform's generator with playable plain-media flashvars, or its list_videos blocks (asynchronous controls, or a container and its _items list), and video pages whose player is gone by the platform's generator, a block's _items list or its screenshot store |
links |
a links:<url> prefix — every supported link on the page |
lulustream |
videos (/<id>, /e/<id>, /d/<id>) whose page names LuluStream and carries its player's HLS source |
mediafire |
file pages (/file/<key>/…) carrying the #downloadButton link, and folder shares (/folder/<key>) whose page is the MediaFire folder viewer |
mediawiki |
MediaWiki categories, articles, file pages and upload lists: pages naming a title (/wiki/<title>, index.php?title=) whose generator is MediaWiki and which carry its ResourceLoader configuration, or whose origin's api.php validates an explicit title or generator-marked page as MediaWiki |
mega |
file and folder links (/file/<handle>#<key>, /folder/<handle>#<key>, /embed/…, #!…!…) whose page is the MEGA web client's boot shell (secureboot.js, #fmholder) |
mixcloud |
shows (/<user>/<show>/, the trailing slash optional) whose page, named Mixcloud, carries the app's cloudcastQuery for the show |
mixdrop |
players (/e/<code>) configuring the MixDrop player object (MDCore), and landing pages (/f/<code>) named MixDrop that frame or configure one |
niconico |
watch pages (/watch/<id>) describing their video in a server-response meta element, and mylists, series and users' uploads rendered by the niconico web client's bundle; live watch pages describing their program in the live client's embedded data, and channels rendered by the channel front end under its portal's name, are handed to yt-dlp |
noodlemagazine |
watch pages (/watch/<id>) named Noodlemagazine carrying the player's window.playlist or the site's watch script, and search listings (/video/<query>) of its video cards or its "nothing found" notice, rendered with its search script |
npo |
episodes and series (/start/afspelen/<slug>, /start/serie/<slug>) of NPO Start, served by its app |
npr |
NPR pages carrying audio players (data-audio): stories, programmes, podcasts and sections |
nrk |
programmes and series (/program/<id>, /serie/<slug>, /se?v=) of NRK TV, whose page data names programmes by prfId |
odysee |
claims (/@<channel>/<claim>) whose page, named Odysee, offers the LBRY embed player (/$/embed/), and channels (/@<channel>) and playlists (/$/playlist/<id>) served by its app bundle |
ok.ru |
videos (/video/<id>, /videoembed/<id>, /live/<id>, a group's or a profile's) whose page mounts the OK video player (OKVideo) with its data-options configuration; group, profile and legacy /dk?st.mvId=<id> links by the embed they name |
orf |
episodes and series (/video/<id>, /sendereihe/<id>, /profile/…) of ORF ON, whose page carries the runtime configuration (__NUXT__) the API credentials are read from; radio broadcasts, podcasts and stories (/radio/…, /player/<date>/<id>, /podcast/…, /stories/<id>) named for the broadcaster are handed to yt-dlp |
pbs |
videos (/video/<slug>/), shows (/show/<slug>/) and player links of PBS, by the player a video page embeds or the videos a show page lists |
peertube |
PeerTube videos, playlists, channels and accounts (/w/<id>, /videos/watch/<id>, /w/p/<id>, /c/<handle>, /a/<handle>) whose page is the PeerTube web client with its inline server configuration, or whose origin's /api/v1/config reports a server version |
pixeldrain |
pixeldrain files, lists and shared directories (/u/<id>, /l/<id>, /d/<id>, /api/file/<id>) served by the software's viewer, which is handed its API root inline, or, for the software's eight-character ids, or any id whose page was withheld, whose origin's API describes exactly that file, list or directory |
pixhost |
galleries (/gallery/<code>) of /thumbs/<group>/<file> thumbnails, and viewer pages (/show/<group>/<file>) showing an img#image from /images/ |
pornhub |
video pages (/view_video.php?viewkey=<key>) named Pornhub whose player configuration (flashvars_<n> with its mediaDefinitions) is in the page, and embeds (/embed/<key>) whose key's video page is |
pornone |
video pages (/<category>/<slug>/<id>/) named PornOne whose player lists renditions as <source> elements named by their frame size |
pornpics |
galleries (/galleries/<slug>) and category, tag, pornstar and channel listings whose page sets the site's PP_LANG global and marks its links rel-link |
radio-canada |
pages of ICI Radio-Canada and OHdio whose data layer (IdsCollection) names their media, media console links read from the link alone, and /media-<id> links named for the site or whose page could not be read |
raiplay |
videos (/video/….html) and programmes (/programmi/<name>) of RaiPlay, whose page mounts its rai-player |
rajce |
albums (/<user>/album/<slug>) whose page assigns the album's settings, media list included, in a script |
redgifs |
clips (/watch/<id>, /ifr/<id>) and users (/users/<name>) served by the RedGIFs app, a clip's page naming its embed player |
rtbf |
media, programmes and live pages of RTBF Auvio (/media/<slug>-<id>, /emission/<slug>-<id>) whose page addresses the Auvio API, and RTBF pages embedding Auvio players |
rtpplay |
episodes and seasons (/play/p<id>[/e<id>]) of RTP Play, whose page carries its player or its episode list |
rtve |
videos and programmes (/play/videos/…, /v/<id>) of RTVE Play, whose page names its asset or programme id |
rumble |
videos (/v<id>-<slug>.html, /embed/v<id>) that the origin's Rumble oEmbed endpoint describes, and channels, users and playlists (/c/<name>, /user/<name>, /playlists/<id>) served by its app bundle |
ruv |
programmes and episodes (/<station>/spila/<slug>/<id>) of RÚV's player, whose page configures its GraphQL endpoint (window._GQL_) |
sendvid |
videos (/<id>, /embed/<id>, and /<id>.mp4, which redirects to the page) whose page, named Sendvid, carries the player's video_source |
soundcloud |
tracks and sets (/<artist>/<track>, /<artist>/sets/<set>) whose page is the SoundCloud web client hydrated with the sound (__sc_hydration) and offering its widget player, private tracks and sets by their secret token (…/s-<token>) hydrated the same way, and artists (/<artist> and its tabs) hydrated the same way |
srf |
programmes and shows of Play SRF (a urn= or a show's id= in the query) whose page names its urn:srf: media |
streamable |
videos (/<id>, /e/<id>, /s/<id>/<slug>) whose page, named Streamable, offers the site's player (/t/<id>) for embedding, or whose video the player's document describes |
streamtape |
videos (/v/<id>, /e/<id>) whose page assembles the Streamtape robotlink media link |
suvobox |
albums (/a/<id>) listing thumb-item tiles, and file pages (/f/<id>) whose download button is the file's own /f/<id>?dl=1 link |
svtplay |
videos (/video/<id>) and programme pages of SVT Play whose page data names the player API's videoSvtIds |
tnaflix |
video pages (/<category>/<slug>/video<id>) named TNAFlix whose player lists its renditions as <source> elements |
turbo |
video pages (/embed/<id>, /d/<id>, /v/<id>) whose player or download page calls the /api/sign?v= signing endpoint, or that frame that player |
vidmoly |
watch pages (/w/<code>, /v/<code>) of the VidMoly app naming the file's player, and players (/embed-<code>.html) whose JWPlayer source list names VidMoly; aliases, and a bare /<code> an alias turned away, are validated against the canonical player |
vids.st |
videos (/v/<id>, /e/<id>) whose page carries the player's playerConfig with its videoUrl |
vimeo |
player pages (/video/<id>) carrying window.playerConfig, and watch pages (/<id>, /<id>/<hash>, channel, group, album and showcase videos, review and manage links) of a site named Vimeo that offer that player for embedding, or whose video's player page does |
voyeurking |
video pages (/video/<slug>) and category and collection listings (/categories/<name>, /collection/<slug>) whose React Router data names the routes/video.$slug, routes/categories or routes/collection route |
vrtmax |
programmes and episodes (/vrtmax/a-z/…) of VRT MAX, served by its app |
wetransfer |
download pages (/downloads/<id>/<hash>) and the short links (/t-<code>) that redirect to them, served by the WeTransfer app with the transfer's securityHash in its page data |
xhamster |
video pages (/videos/<slug>-<id>) named xHamster that carry the site's page state (window.initials) and player settings |
yandex |
video search previews (/video/preview/<id>, /video/search?filmId=<id>, their touch forms) built by the Yandex search front end, naming the source video in its viewer |
yle |
programmes and series (…/1-<id>) of Yle Areena, whose page carries the Areena web app's configuration |
youtube |
videos (/watch?v=<id>, /shorts/<id>, /embed/<id>, /clip/<id>), playlists, channels and their tabs, searches, hashtags and music pages whose page carries the YouTube web client's configuration (ytcfg) beside its player or page data or under the YouTube Music name, or the consent form that stands in for such a page; a video, embed, playlist or /channel/UC<id> link whose probe was refused or failed |
zdf |
videos and show pages (/…/<slug>-<number>) of the ZDF Mediathek, whose page data names its PTMD player templates, and documents of its metadata API (/mediathekV2/document/<id>) |
See the feature guide for transfer behavior, queue controls, naming, image-board support and recovery details.
Light theme, mobile layout and terminal mode
Use -debug=false for animated terminal progress. Debug logs are enabled by
default; pipes and log files always receive plain progress lines.
Start with the documentation index. If you are reading this inside a release archive, the full online documentation is available on GitHub.
Flags and environment variables cover download locations, concurrency, bandwidth, queue state and proxy settings. Flags take precedence over environment variables.
Media helpers, local OCR and proxies explains which workflows need extra tools, how to install them, and their platform limits. The Docker image includes them.
Use the HTTP API reference to submit downloads, change settings or consume the event stream.
HeapLeach is a single-user service without authentication. Anyone who can reach its API can inspect the queue, submit downloads and change the destination. Use a loopback address locally; remote access needs an authenticated HTTPS reverse proxy and restricted access to the backend port. Read the network guide.
The architecture guide follows a URL from extraction to disk and explains the package dependency rules.
To try a source build on Linux, install Git, GNU Make and Docker, then:
git clone https://github.com/JohanLindvall/HeapLeach.git
cd HeapLeach
make build
./bin/heapleachDocker produces a Linux executable. On macOS or Windows, use the prebuilt release, run the Docker image, or follow the native development setup.
For hot reload, install the Go toolchain and Node.js 24, run npm ci in
frontend/, then make dev from the root. See
CONTRIBUTING.md for the complete setup and checks, and
the development reference for build targets and releases.
Jump to source layout, adding a host or release packaging.
Bug reports, documentation improvements, UI fixes and new extractors are welcome. You do not need to know the whole codebase to help.
- Read the contribution guide for setup and suggested starting points.
- Report a bug or request a feature.
- Get help or report a vulnerability privately.
- Follow the code of conduct.
If HeapLeach is useful to you, star the repository to help others find it. Sharing a clear bug report or a small improvement helps the project too.
Why “HeapLeach”?
Heap leaching is a mining method: crushed ore is piled into a heap and irrigated from above, and the solution percolates down through it, dissolving out the metal as it goes and draining to a pad at the bottom. This does the same to a heap of links. The extractors percolate through whatever the pages are made of — players, listings, signed redirects, encrypted payloads — and what is worth keeping drains out into a folder.
The operating notes explain queue checkpoints, partial files and live-site tests. Use modest concurrency and respect host limits.
HeapLeach is MIT licensed. Bundled OCR assets and external media
helpers retain their own licenses; see the notices in ocr/ and the
OCR packaging guide.


