Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

ytdlp-nodejs

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ytdlp-nodejs - npm Package Compare versions

Comparing version
2.3.5
to
3.3.6
+26
dist/cli/index.js
#!/usr/bin/env node
#!/usr/bin/env node
"use strict";var st=Object.create;var xe=Object.defineProperty;var nt=Object.getOwnPropertyDescriptor;var ot=Object.getOwnPropertyNames;var it=Object.getPrototypeOf,at=Object.prototype.hasOwnProperty;var ut=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of ot(t))!at.call(e,n)&&n!==r&&xe(e,n,{get:()=>t[n],enumerable:!(s=nt(t,n))||s.enumerable});return e};var m=(e,t,r)=>(r=e!=null?st(it(e)):{},ut(t||!e||!e.__esModule?xe(r,"default",{value:e,enumerable:!0}):r,e));var Pe=m(require("fs")),te=m(require("path"));function lt(){try{let e=te.default.resolve(__dirname,"..","package.json"),t=Pe.default.readFileSync(e,"utf8");return JSON.parse(t).version||"0.0.0"}catch{return"0.0.0"}}function ft(e){return e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase())}function ve(e){let t,r=[],s={},n=[],o=[...e];o[0]&&!o[0].startsWith("-")&&(t=o.shift());for(let a=0;a<o.length;a++){let u=o[a];if(u==="--"){n.push(...o.slice(a+1));break}if(u.startsWith("--")){let l=u.indexOf("="),c=l===-1?u.slice(2):u.slice(2,l),f=!0;if(l!==-1?f=u.slice(l+1):o[a+1]&&!o[a+1].startsWith("-")&&(f=o[a+1],a+=1),c==="raw"){f===!0?o[a+1]&&(n.push(o[a+1]),a+=1):n.push(String(f));continue}s[c]===void 0?s[c]=f:Array.isArray(s[c])?s[c]=[...s[c],String(f)]:s[c]=[String(s[c]),String(f)]}else r.push(u)}let i={};for(let[a,u]of Object.entries(s))i[ft(a)]=u;if(i.raw){let a=i.raw;Array.isArray(a)?n.push(...a.map(String)):typeof a=="string"&&n.push(a)}return n.length>0&&(i.raw=n),{command:t,positionals:r,options:i}}function L(e){if(e.length===0)return"No formats found.";let t=["format","ext","resolution","note"],r=[Math.max(t[0].length,...e.map(n=>n.formatId.length)),Math.max(t[1].length,...e.map(n=>n.extension.length)),Math.max(t[2].length,...e.map(n=>n.resolution.length))],s=[`${t[0].padEnd(r[0])} ${t[1].padEnd(r[1])} ${t[2].padEnd(r[2])} ${t[3]}`,`${"-".repeat(r[0])} ${"-".repeat(r[1])} ${"-".repeat(r[2])} ${"-".repeat(t[3].length)}`];for(let n of e)s.push(`${n.formatId.padEnd(r[0])} ${n.extension.padEnd(r[1])} ${n.resolution.padEnd(r[2])} ${n.note}`);return s.join(`
`)}function ct(e){if(e)return te.default.join(e,"%(title)s.%(ext)s")}function j(e,t){t.proxy&&!e.proxy&&(e.proxy=t.proxy),t.cookiesPath&&!e.cookies&&(e.cookies=t.cookiesPath),t.concurrency&&!e.concurrentFragments&&(e.concurrentFragments=t.concurrency),t.verbose&&!e.verbose&&(e.verbose=!0),t.downloadDir&&!e.output&&(e.output=ct(t.downloadDir))}function M(e,t){let r={};return e.output&&(r.output=String(e.output)),e.proxy&&(r.proxy=String(e.proxy)),e.cookies&&(r.cookies=String(e.cookies)),e.cookiesFromBrowser&&(r.cookiesFromBrowser=String(e.cookiesFromBrowser)),e.socketTimeout&&(r.socketTimeout=Number(e.socketTimeout)),e.concurrentFragments&&(r.concurrentFragments=Number(e.concurrentFragments)),e.retries&&(r.retries=Number(e.retries)),e.retrySleep&&(r.retrySleep=Number(e.retrySleep)),e.limitRate&&(r.limitRate=String(e.limitRate)),e.downloadSections&&(r.downloadSections=String(e.downloadSections)),e.playlistItems&&(r.playlistItems=String(e.playlistItems)),e.noPlaylist&&(r.noPlaylist=!0),e.formatSort&&(r.formatSort=String(e.formatSort).split(",").map(s=>s.trim()).filter(Boolean)),e.mergeOutputFormat&&(r.mergeOutputFormat=String(e.mergeOutputFormat)),e.raw&&(r.rawArgs=e.raw),e.verbose&&(r.verbose=!0),j(r,t),r}function Se(e,t){return e.format?String(e.format):e.audioOnly?{filter:"audioonly",type:e.audioFormat?String(e.audioFormat):"mp3",quality:e.audioQuality?Number(e.audioQuality):5}:t.defaultFormat}function re(e,t,r){let s=t.subLangs?String(t.subLangs).split(",").map(n=>n.trim()).filter(Boolean):r.subtitles?.languages;s&&s.length>0&&(e.subLangs=s),t.subFormat?e.subFormat=String(t.subFormat):r.subtitles?.format&&(e.subFormat=r.subtitles.format),t.writeSubs&&(e.writeSubs=!0),t.writeAutoSubs&&(e.writeAutoSubs=!0),t.embedSubs&&(e.embedSubs=!0),r.subtitles?.embed&&!e.embedSubs&&(e.embedSubs=!0),r.subtitles?.auto&&!e.writeAutoSubs&&(e.writeAutoSubs=!0)}function se(e,t,r){let s=t.sponsorblockCategories?String(t.sponsorblockCategories).split(",").map(o=>o.trim()).filter(Boolean):r.sponsorblock?.categories,n=t.sponsorblockMode?String(t.sponsorblockMode):r.sponsorblock?.mode;s&&s.length>0&&(n==="mark"&&(e.sponsorblockMark=s),n==="remove"&&(e.sponsorblockRemove=s))}function K(e){return t=>{process.stdout.write(`${e} ${t.percentage_str}\r`)}}function y(){console.log(`ytdlp-nodejs ${lt()}
Usage:
ytdlp-nodejs Launch interactive mode
ytdlp-nodejs download <url> Download a video
ytdlp-nodejs info <url> Get info as JSON
ytdlp-nodejs formats <url> List formats
ytdlp-nodejs urls <url> Get direct URLs
ytdlp-nodejs subs <url> Download subtitles only
ytdlp-nodejs sponsorblock <url> Download with SponsorBlock
ytdlp-nodejs sections <url> Download sections/time range
ytdlp-nodejs update Update yt-dlp
ytdlp-nodejs config Show or set CLI config
`)}var B=require("child_process"),J=m(require("fs")),Qe=m(require("path"));function k(e){let t=[];if(e.printHelp&&t.push("--help"),e.printVersion&&t.push("--version"),e.update&&t.push("--update"),e.noUpdate&&t.push("--no-update"),e.updateTo&&t.push("--update-to",e.updateTo),e.ignoreErrors&&t.push("--ignore-errors"),e.noAbortOnError&&t.push("--no-abort-on-error"),e.abortOnError&&t.push("--abort-on-error"),e.dumpUserAgent&&t.push("--dump-user-agent"),e.listExtractors&&t.push("--list-extractors"),e.extractorDescriptions&&t.push("--extractor-descriptions"),e.useExtractors&&e.useExtractors.length>0&&t.push("--use-extractors",e.useExtractors.join(",")),e.defaultSearch&&t.push("--default-search",e.defaultSearch),e.ignoreConfig&&t.push("--ignore-config"),e.noConfigLocations&&t.push("--no-config-location"),e.configLocations&&e.configLocations.length>0&&t.push("--config-locations",...e.configLocations),e.pluginDirs&&e.pluginDirs.length>0)for(let s of e.pluginDirs)t.push("--plugin-dirs",s);e.noPluginDirs&&t.push("--no-plugin-dirs"),e.flatPlaylist&&t.push("--flat-playlist"),e.noFlatPlaylist&&t.push("--no-flat-playlist"),e.liveFromStart&&t.push("--live-from-start"),e.noLiveFromStart&&t.push("--no-live-from-start"),e.waitForVideo&&t.push("--wait-for-video",e.waitForVideo.toString()),e.noWaitForVideo&&t.push("--no-wait-for-video"),e.markWatched&&t.push("--mark-watched"),e.noMarkWatched&&t.push("--no-mark-watched"),e.color&&t.push("--color",e.color),e.compatOptions&&e.compatOptions.length>0&&t.push("--compat-options",e.compatOptions.join(",")),e.aliases&&e.aliases.length>0&&t.push("--alias",...e.aliases);let r=e.jsRuntime??"node";if(r&&t.push("--js-runtime",r),e.proxy&&t.push("--proxy",e.proxy),e.socketTimeout&&t.push("--socket-timeout",e.socketTimeout.toString()),e.sourceAddress&&t.push("--source-address",e.sourceAddress),e.impersonate&&e.impersonate.length>0&&t.push("--impersonate",e.impersonate.join(",")),e.listImpersonateTargets&&t.push("--list-impersonate-targets"),e.forceIpv4&&t.push("--force-ipv4"),e.forceIpv6&&t.push("--force-ipv6"),e.enableFileUrls&&t.push("--enable-file-urls"),e.geoVerificationProxy&&t.push("--geo-verification-proxy",e.geoVerificationProxy),e.xff&&t.push("--xff",e.xff),e.playlistItems&&t.push("--playlist-items",e.playlistItems),e.minFilesize&&t.push("--min-filesize",e.minFilesize),e.maxFilesize&&t.push("--max-filesize",e.maxFilesize),e.date&&t.push("--date",e.date),e.dateBefore&&t.push("--datebefore",e.dateBefore),e.dateAfter&&t.push("--dateafter",e.dateAfter),e.matchFilter&&t.push("--match-filter",e.matchFilter),e.noMatchFilters&&t.push("--no-match-filters"),e.breakMatchFilters&&t.push("--break-match-filters",e.breakMatchFilters),e.noBreakMatchFilters&&t.push("--no-break-match-filters"),e.noPlaylist&&t.push("--no-playlist"),e.yesPlaylist&&t.push("--yes-playlist"),e.ageLimit&&t.push("--age-limit",e.ageLimit.toString()),e.downloadArchive&&t.push("--download-archive",e.downloadArchive),e.noDownloadArchive&&t.push("--no-download-archive"),e.maxDownloads&&t.push("--max-downloads",e.maxDownloads.toString()),e.breakOnExisting&&t.push("--break-on-existing"),e.noBreakOnExisting&&t.push("--no-break-on-existing"),e.breakPerInput&&t.push("--break-per-input"),e.noBreakPerInput&&t.push("--break-per-input"),e.skipPlaylistAfterErrors&&t.push("--skip-playlist-after-errors",e.skipPlaylistAfterErrors.toString()),e.concurrentFragments&&t.push("--concurrent-fragments",e.concurrentFragments.toString()),e.limitRate&&t.push("--limit-rate",e.limitRate),e.throttledRate&&t.push("--throttled-rate",e.throttledRate),e.retries&&t.push("--retries",e.retries.toString()),e.fileAccessRetries&&t.push("--file-access-retries",e.fileAccessRetries.toString()),e.fragmentRetries&&t.push("--fragment-retries",e.fragmentRetries.toString()),e.retrySleep&&t.push("--retry-sleep",e.retrySleep.toString()),e.retrySleepByType)for(let[s,n]of Object.entries(e.retrySleepByType))t.push("--retry-sleep",`${s}:${n}`);if(e.skipUnavailableFragments&&t.push("--skip-unavailable-fragments"),e.abortOnUnavailableFragment&&t.push("--abort-on-unavailable-fragment"),e.keepFragments&&t.push("--keep-fragments"),e.noKeepFragments&&t.push("--no-keep-fragments"),e.bufferSize&&t.push("--buffer-size",e.bufferSize),e.resizeBuffer&&t.push("--resize-buffer"),e.noResizeBuffer&&t.push("--no-resize-buffer"),e.httpChunkSize&&t.push("--http-chunk-size",e.httpChunkSize),e.playlistRandom&&t.push("--playlist-random"),e.lazyPlaylist&&t.push("--lazy-playlist"),e.noLazyPlaylist&&t.push("--no-lazy-playlist"),e.xattrSetFilesize&&t.push("--xattr-set-filesize"),e.hlsUseMpegts&&t.push("--hls-use-mpegts"),e.noHlsUseMpegts&&t.push("--no-hls-use-mpegts"),e.downloadSections&&t.push("--download-sections",e.downloadSections.toString()),e.downloader&&t.push("--downloader",e.downloader),e.downloaderArgs&&t.push("--downloader-args",e.downloaderArgs),e.batchFile&&t.push("--batch-file",e.batchFile),e.noBatchFile&&t.push("--no-batch-file"),e.paths)if(typeof e.paths=="string")t.push("--paths",e.paths);else for(let[s,n]of Object.entries(e.paths))t.push("--paths",`${s}:${n}`);if(e.output&&t.push("-o",e.output),e.outputNaPlaceholder&&t.push("--output-na-placeholder",e.outputNaPlaceholder),e.restrictFilenames&&t.push("--restrict-filenames"),e.noRestrictFilenames&&t.push("--no-restrict-filenames"),e.windowsFilenames&&t.push("--windows-filenames"),e.noWindowsFilenames&&t.push("--no-windows-filenames"),e.trimFileNames&&t.push("--trim-file-names",e.trimFileNames.toString()),e.noOverwrites&&t.push("--no-overwrites"),e.forceOverwrites&&t.push("--force-overwrites"),e.noForceOverwrites&&t.push("--no-force-overwrites"),e.continue&&t.push("--continue"),e.noContinue&&t.push("--no-continue"),e.part&&t.push("--part"),e.noPart&&t.push("--no-part"),e.mtime&&t.push("--mtime"),e.noMtime&&t.push("--no-mtime"),e.writeDescription&&t.push("--write-description"),e.noWriteDescription&&t.push("--no-write-description"),e.writeInfoJson&&t.push("--write-info-json"),e.noWriteInfoJson&&t.push("--no-write-info-json"),e.writePlaylistMetafiles&&t.push("--write-playlist-metafiles"),e.noWritePlaylistMetafiles&&t.push("--no-write-playlist-metafiles"),e.cleanInfoJson&&t.push("--clean-info-json"),e.noCleanInfoJson&&t.push("--no-clean-info-json"),e.writeComments&&t.push("--write-comments"),e.noWriteComments&&t.push("--no-write-comments"),e.loadInfoJson&&t.push("--load-info-json",e.loadInfoJson.toString()),e.cookies&&t.push("--cookies",e.cookies),e.noCookies&&t.push("--no-cookies"),e.cookiesFromBrowser&&t.push("--cookies-from-browser",e.cookiesFromBrowser),e.noCookiesFromBrowser&&t.push("--no-cookies-from-browser"),e.cacheDir&&t.push("--cache-dir",e.cacheDir),e.noCacheDir&&t.push("--no-cache-dir"),e.rmCacheDir&&t.push("--rm-cache-dir"),e.writeThumbnail&&t.push("--write-thumbnail"),e.noWriteThumbnails&&t.push("--no-write-thumbnails"),e.writeAllThumbnails&&t.push("--write-all-thumbnails"),e.listThumbnails&&t.push("--list-thumbnails"),e.writeLink&&t.push("--write-link"),e.writeUrlLink&&t.push("--write-url-link"),e.writeWeblocLink&&t.push("--write-webloc-link"),e.writeDesktopLink&&t.push("--write-desktop-link"),e.quiet&&t.push("--quiet"),e.noQuiet&&t.push("--no-quiet"),e.noWarnings&&t.push("--no-warnings"),e.simulate&&t.push("--simulate"),e.noSimulate&&t.push("--no-simulate"),e.ignoreNoFormatsError&&t.push("--ignore-no-formats-error"),e.noIgnoreNoFormatsError&&t.push("--no-ignore-no-formats-error"),e.skipDownload&&t.push("--skip-download"),e.print&&t.push("--print",e.print),e.printToFile&&t.push("--print-to-file",e.printToFile),e.dumpJson&&t.push("--dump-json"),e.dumpSingleJson&&t.push("--dump-single-json"),e.forceWriteArchive&&t.push("--force-write-archive"),e.newline&&t.push("--newline"),e.noProgress&&t.push("--no-progress"),e.progress&&t.push("--progress"),e.consoleTitle&&t.push("--console-title"),e.progressTemplate&&t.push("--progress-template",e.progressTemplate),e.progressDelta&&t.push("--progress-delta",e.progressDelta.toString()),e.verbose&&t.push("--verbose"),e.dumpPages&&t.push("--dump-pages"),e.writePages&&t.push("--write-pages"),e.printTraffic&&t.push("--print-traffic"),e.encoding&&t.push("--encoding",e.encoding),e.legacyServerConnect&&t.push("--legacy-server-connect"),e.noCheckCertificates&&t.push("--no-check-certificates"),e.preferInsecure&&t.push("--prefer-insecure"),e.addHeaders)for(let[s,n]of Object.entries(e.addHeaders))t.push("--add-header",`${s}:${n}`);if(e.headers)for(let[s,n]of Object.entries(e.headers))t.push("--add-header",`${s}:${n}`);if(e.bidiWorkaround&&t.push("--bidi-workaround"),e.sleepRequests&&t.push("--sleep-requests",e.sleepRequests.toString()),e.sleepInterval&&t.push("--sleep-interval",e.sleepInterval.toString()),e.maxSleepInterval&&t.push("--max-sleep-interval",e.maxSleepInterval.toString()),e.sleepSubtitles&&t.push("--sleep-subtitles",e.sleepSubtitles.toString()),e.format&&t.push("-f",e.format),e.formatSort&&e.formatSort.length>0&&t.push("--format-sort",e.formatSort.join(",")),e.formatSortForce&&t.push("--format-sort-force"),e.noFormatSortForce&&t.push("--no-format-sort-force"),e.videoMultiStreams&&t.push("--video-multistreams"),e.noVideoMultiStreams&&t.push("--no-video-multistreams"),e.audioMultiStreams&&t.push("--audio-multistreams"),e.noAudioMultiStreams&&t.push("--no-audio-multistreams"),e.preferFreeFormats&&t.push("--prefer-free-formats"),e.noPreferFreeFormats&&t.push("--no-prefer-free-formats"),e.checkFormats&&t.push("--check-formats"),e.checkAllFormats&&t.push("--check-all-formats"),e.noCheckFormats&&t.push("--no-check-formats"),e.listFormats&&t.push("--list-formats"),e.mergeOutputFormat&&t.push("--merge-output-format",e.mergeOutputFormat),e.writeSubs&&t.push("--write-subs"),e.noWriteSubs&&t.push("--no-write-subs"),e.writeAutoSubs&&t.push("--write-auto-subs"),e.writeAllSubs&&t.push("--all-subs"),e.listSubs&&t.push("--list-subs"),e.subFormat&&t.push("--sub-format",e.subFormat),e.subLangs&&e.subLangs.length>0&&t.push("--sub-langs",e.subLangs.join(",")),e.username&&t.push("--username",e.username),e.password&&t.push("--password",e.password),e.twoFactor&&t.push("--twofactor",e.twoFactor),e.netrc&&t.push("--netrc"),e.videoPassword&&t.push("--video-password",e.videoPassword),e.apMso&&t.push("--ap-mso",e.apMso),e.apUsername&&t.push("--ap-username",e.apUsername),e.apPassword&&t.push("--ap-password",e.apPassword),e.netrcLocation&&t.push("--netrc-location",e.netrcLocation),e.netrcCmd&&t.push("--netrc-cmd",e.netrcCmd),e.apListMso&&t.push("--ap-list-mso"),e.clientCertificate&&t.push("--client-certificate",e.clientCertificate),e.clientCertificateKey&&t.push("--client-certificate-key",e.clientCertificateKey),e.clientCertificatePassword&&t.push("--client-certificate-password",e.clientCertificatePassword),e.extractorRetries!==void 0&&t.push("--extractor-retries",e.extractorRetries.toString()),e.allowDynamicMpd&&t.push("--allow-dynamic-mpd"),e.ignoreDynamicMpd&&t.push("--ignore-dynamic-mpd"),e.hlsSplitDiscontinuity&&t.push("--hls-split-discontinuity"),e.noHlsSplitDiscontinuity&&t.push("--no-hls-split-discontinuity"),e.extractorArgs)for(let[s,n]of Object.entries(e.extractorArgs))t.push("--extractor-args",`${s}:${n.join(" ")}`);if(e.playlistStart!==void 0&&t.push("--playlist-start",e.playlistStart.toString()),e.playlistEnd!==void 0&&t.push("--playlist-end",e.playlistEnd.toString()),e.matchTitle&&t.push("--match-title",e.matchTitle),e.rejectTitle&&t.push("--reject-title",e.rejectTitle),e.includeAds&&t.push("--include-ads"),e.breakOnReject&&t.push("--break-on-reject"),e.noDownload&&t.push("--no-download"),e.playlistReverse&&t.push("--playlist-reverse"),e.geoBypass&&t.push("--geo-bypass"),e.geoBypassCountry&&t.push("--geo-bypass-country",e.geoBypassCountry),e.geoBypassIpBlock&&t.push("--geo-bypass-ip-block",e.geoBypassIpBlock),e.convertThumbnails&&t.push("--convert-thumbnails",e.convertThumbnails),e.writeLink&&t.push("--write-link"),e.writeUrlLink&&t.push("--write-url-link"),e.writeWeblocLink&&t.push("--write-webloc-link"),e.writeLnkLink&&t.push("--write-lnk-link"),e.referer&&t.push("--referer",e.referer),e.userAgent&&t.push("--user-agent",e.userAgent),e.extractAudio&&t.push("--extract-audio"),e.audioFormat&&t.push("--audio-format",e.audioFormat),e.audioQuality&&t.push("--audio-quality",e.audioQuality),e.remuxVideo&&t.push("--remux-video",e.remuxVideo),e.recodeVideo&&t.push("--recode-video",e.recodeVideo),e.postprocessorArgs)for(let[s,n]of Object.entries(e.postprocessorArgs))t.push("--postprocessor-args",`${s}:${n.join(" ")}`);if(e.keepVideo&&t.push("--keep-video"),e.noKeepVideo&&t.push("--no-keep-video"),e.postOverwrites&&t.push("--post-overwrites"),e.noPostOverwrites&&t.push("--no-post-overwrites"),e.embedSubs&&t.push("--embed-subs"),e.noEmbedSubs&&t.push("--no-embed-subs"),e.embedThumbnail&&t.push("--embed-thumbnail"),e.noEmbedThumbnail&&t.push("--no-embed-thumbnail"),e.embedMetadata&&t.push("--embed-metadata"),e.noEmbedMetadata&&t.push("--no-embed-metadata"),e.embedChapters&&t.push("--embed-chapters"),e.noEmbedChapters&&t.push("--no-embed-chapters"),e.embedInfoJson&&t.push("--embed-info-json"),e.noEmbedInfoJson&&t.push("--no-embed-info-json"),e.parseMetadata)for(let[s,n]of Object.entries(e.parseMetadata))t.push("--parse-metadata",`${s}:${n}`);if(e.replaceInMetadata)for(let[s,[n,o]]of Object.entries(e.replaceInMetadata))t.push("--replace-in-metadata",`${s} ${n} ${o}`);if(e.xattrs&&t.push("--xattrs"),e.concatPlaylist&&t.push("--concat-playlist",e.concatPlaylist),e.fixup&&t.push("--fixup",e.fixup),e.ffmpegLocation&&t.push("--ffmpeg-location",e.ffmpegLocation),e.exec&&t.push("--exec",e.exec),e.noExec&&t.push("--no-exec"),e.convertSubs&&t.push("--convert-subs",e.convertSubs),e.convertThumbnails&&t.push("--convert-thumbnails",e.convertThumbnails),e.splitChapters&&t.push("--split-chapters"),e.noSplitChapters&&t.push("--no-split-chapters"),e.removeChapters&&t.push("--remove-chapters",e.removeChapters),e.noRemoveChapters&&t.push("--no-remove-chapters"),e.forceKeyframesAtCuts&&t.push("--force-keyframes-at-cuts"),e.noForceKeyframesAtCuts&&t.push("--no-force-keyframes-at-cuts"),e.usePostProcessor&&e.usePostProcessor.length>0)for(let s of e.usePostProcessor)t.push("--use-postprocessor",s);return e.sponsorblockMark&&e.sponsorblockMark.length>0&&t.push("--sponsorblock-mark",e.sponsorblockMark.join(",")),e.sponsorblockRemove&&e.sponsorblockRemove.length>0&&t.push("--sponsorblock-remove",e.sponsorblockRemove.join(",")),e.sponsorblockChapterTitle&&t.push("--sponsorblock-chapter-title",e.sponsorblockChapterTitle),e.noSponsorblock&&t.push("--no-sponsorblock"),e.sponsorblockApi&&t.push("--sponsorblock-api",e.sponsorblockApi),e.additionalOptions&&e.additionalOptions.length>0&&t.push(...e.additionalOptions),e.rawArgs&&e.rawArgs.length>0&&t.push(...e.rawArgs),t}function ne(e){let t=[],r=e.split(`
`).slice(1);for(let s of r){let n=s.match(/(\d+)\s+(\S+)\s+(\S+)\s+(https:\/\/[\S]+)/);n&&t.push({id:parseInt(n[1],10),width:n[2]==="unknown"?"unknown":parseInt(n[2],10),height:n[3]==="unknown"?"unknown":parseInt(n[3],10),url:n[4]})}return t}var ke={"2160p":"bv*[height<=2160]","1440p":"bv*[height<=1440]","1080p":"bv*[height<=1080]","720p":"bv*[height<=720]","480p":"bv*[height<=480]","360p":"bv*[height<=360]","240p":"bv*[height<=240]","144p":"bv*[height<=133]",highest:"bv*",lowest:"wv*"};function $(e){if(!e)return[];if(typeof e=="string")return["-f",e];if(Object.keys(e).length===0)return["-f","bv*+ba"];let t=[],{filter:r,quality:s,type:n}=e;return r==="audioonly"&&(t=["-x","--audio-format",n||"mp3","--audio-quality",s?s.toString():"5"]),r==="videoonly"&&(t=["-f",(s?ke[s]:"bv*")+"[acodec=none]"]),r==="audioandvideo"&&(t=["-f",(s=="lowest"?"w*":"b*")+"[vcodec!=none][acodec!=none][ext="+(n||"mp4")+"]"]),r==="mergevideo"&&(t=["-f",`${s?ke[s]:"bv*"}+ba`],n&&t.push("--merge-output-format",n)),t}function oe(e){if(!e||typeof e=="string")return"video/mp4";let{filter:t,type:r}=e;switch(t){case"videoonly":case"audioandvideo":switch(r){case"mp4":return"video/mp4";case"webm":return"video/webm";default:return"video/mp4"}case"audioonly":switch(r){case"aac":return"audio/aac";case"flac":return"audio/flac";case"mp3":return"audio/mp3";case"m4a":return"audio/mp4";case"opus":return"audio/opus";case"vorbis":return"audio/vorbis";case"wav":return"audio/wav";case"alac":return"audio/mp4";default:return"audio/mpeg"}case"mergevideo":switch(r){case"webm":return"video/webm";case"mkv":return"video/x-matroska";case"ogg":return"video/ogg";case"flv":return"video/x-flv";default:return"video/mp4"}}}function Fe(e){if(!e?.extractAudio)return null;switch(e.audioFormat||"mp3"){case"aac":return"audio/aac";case"flac":return"audio/flac";case"mp3":return"audio/mpeg";case"m4a":return"audio/mp4";case"opus":return"audio/opus";case"vorbis":return"audio/vorbis";case"wav":return"audio/wav";case"alac":return"audio/mp4";default:return"audio/mpeg"}}var ae="~ytdlp-progress-%(progress)#j";function ie(e,t=2){let r=Number(e);if(r===0||isNaN(r))return r+" Bytes";let s=1024,n=t<0?0:t,o=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],i=Math.floor(Math.log(r)/Math.log(s));return parseFloat((r/Math.pow(s,i)).toFixed(n))+" "+o[i]}function dt(e,t,r){let s=Math.pow(r||10,t);return Math.round(e*s)/s}function pt(e){e=Number(e);let t=Math.floor(e/3600),r=Math.floor(e%3600/60),s=Math.floor(e%3600%60),n=t>0?t+(t==1?" hour, ":" hours, "):"",o=r>0?r+(r==1?" minute, ":" minutes, "):"",i=s>=0?s+(s==1?" second":" seconds"):"";return n+o+i}function F(e){try{if(!e.includes("~ytdlp-progress-"))throw new Error;let t=e.trim().replace("~ytdlp-progress-","");if(!t)throw new Error;let r=JSON.parse(t),s=l=>{if(l==null||l==="NA")return;let c=Number(l);return isNaN(c)?void 0:c},n=s(r.downloaded_bytes),o=s(r.total_bytes)??s(r.total_bytes_estimate),i=s(r.speed),a=s(r.eta),u=n!==void 0&&o!==void 0&&o>0?dt(100*n/o,2):void 0;return{filename:r.filename,status:r.status,downloaded:n,downloaded_str:n!==void 0?ie(n):void 0,total:o,total_str:o!==void 0?ie(o):void 0,speed:i,speed_str:i!==void 0?ie(i)+"/s":void 0,eta:a,eta_str:a!==void 0?pt(a):void 0,percentage:u,percentage_str:u!==void 0?u+"%":void 0}}catch{return}}var q=m(require("path")),U=m(require("fs"));var mt=m(require("https")),gt=m(require("http")),ue=require("url"),x=m(require("fs"));function le(e,t={}){return new Promise((r,s)=>{let i=(new ue.URL(e).protocol==="https:"?mt:gt).get(e,t,a=>{if(a.statusCode>=300&&a.statusCode<400&&a.headers.location){let u=new ue.URL(a.headers.location,e).toString();le(u,t).then(r).catch(s);return}r(a)});i.on("error",s),i.setTimeout(3e4,()=>{i.destroy(),s(new Error("Request timed out"))})})}async function V(e,t){try{let r=x.createWriteStream(t),s=await le(e);if(s.statusCode!==200)throw r.close(),x.unlinkSync(t),new Error(`Failed to download file: ${s.statusCode} ${s.statusMessage}`);let n=parseInt(s.headers["content-length"]||"0",10),o=0;return s.on("data",i=>{o+=i.length;let a=o/n*100;process.stdout.write(`Progress: ${Math.round(a)}%\r`)}),s.pipe(r),new Promise((i,a)=>{r.on("finish",()=>{r.close(),console.log(`
Download complete!`),i()}),r.on("error",u=>{r.close(),x.unlinkSync(t),a(u)}),s.on("error",u=>{r.close(),x.unlinkSync(t),a(u)})})}catch(r){throw x.existsSync(t)&&x.unlinkSync(t),r}}async function Ce(e,t={}){let r=await le(e,t);if(r.statusCode!==200)throw new Error(`Failed to fetch text: ${r.statusCode} ${r.statusMessage}`);return new Promise((s,n)=>{let o="";r.setEncoding("utf8"),r.on("data",i=>{o+=i}),r.on("end",()=>s(o)),r.on("error",n)})}var Ae=m(require("fs")),E=m(require("path"));function ht(e){let t=e;for(;;){if(Ae.existsSync(E.join(t,"package.json")))return t;let r=E.dirname(t);if(r===t)return e;t=r}}var De=ht(__dirname),C=E.join(De,"bin"),tr=E.join(De,"package.json");var yt="https://github.com/iqbal-rashed/ytdlp-nodejs/releases/download/ffmpeg-latest",fe={win32:{x64:["win-x64-ffmpeg.exe","win-x64-ffprobe.exe"],ia32:["win-ia32-ffmpeg.exe","win-ia32-ffprobe.exe"],arm64:["win-arm64-ffmpeg.exe","win-arm64-ffprobe.exe"]},linux:{x64:["linux-x64-ffmpeg","linux-x64-ffprobe"],arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]},darwin:{x64:["macos-x64-ffmpeg","macos-x64-ffprobe"],arm64:["macos-arm64-ffmpeg","macos-arm64-ffprobe"]},android:{arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]}};function Oe(){let e=process.platform,t=process.arch;if(!fe[e]||!fe[e][t])throw new Error(`No FFmpeg build available for platform: ${e}, architecture: ${t}`);return fe[e][t]}async function Ie(e){let t=e||C,r=G();if(r)return r;try{let s=Oe();if(!s.length)throw new Error;let n=s.map(i=>`${yt}/${i}`),o=s.map(i=>q.default.join(t,String(i.split("-").pop())));U.default.existsSync(t)||U.default.mkdirSync(t,{recursive:!0}),console.log("Downloading FFmpeg and FFprobe...");for(let i=0;i<s.length;i++){let a=n[i],u=o[i];console.log("Downloading...",q.default.basename(a)),await V(a,u)}try{for(let i of o)U.default.chmodSync(i,493)}catch{console.log("Note: Could not set executable permissions (likely Windows)")}return G()}catch(s){throw console.error(`Download failed: ${s}`),s}}function G(){try{let e=Oe();if(!e.length)throw new Error;let t=q.default.join(C,String(e[0].split("-").pop()));if(!U.default.existsSync(t))throw new Error("FFmpeg binary not found. Please download it first.");return t}catch{return}}var b=m(require("fs")),Y=m(require("path"));var Re=m(require("crypto")),Te="https://github.com/yt-dlp/yt-dlp/releases/latest/download",H={win32:{x64:"yt-dlp.exe",ia32:"yt-dlp_x86.exe"},linux:{x64:"yt-dlp",armv7l:"yt-dlp_linux_armv7l",aarch64:"yt-dlp_linux_aarch64",arm64:"yt-dlp"},darwin:{x64:"yt-dlp_macos",arm64:"yt-dlp_macos"},android:{arm64:"yt-dlp"}};function bt(){let e=process.platform,t=process.arch;if(!H[e]||!H[e][t])throw new Error(`No yt-dlp build available for ${e} ${t}`);return H[e][t]}async function ce(e){let t=e||C,r=bt(),s=`${Te}/${r}`,n=Y.join(t,r);if(b.existsSync(n))return n;console.log("Downloading yt-dlp...",s),b.existsSync(t)||b.mkdirSync(t,{recursive:!0});try{await V(s,n),console.log(`yt-dlp downloaded successfully to: ${n}`);try{b.chmodSync(n,493)}catch{console.log("Error while chmod")}return n}catch(i){throw console.error(`Download failed: ${i}`),i}}async function wt(e){return new Promise((t,r)=>{let s=Re.default.createHash("sha256"),n=b.createReadStream(e);n.on("data",o=>s.update(o)),n.on("end",()=>t(s.digest("hex"))),n.on("error",r)})}async function xt(e){try{let s=(await Ce(`${Te}/SHA2-256SUMS`)).split(/\r?\n/).find(o=>o.includes(e));if(!s)return;let[n]=s.trim().split(/\s+/);return n||void 0}catch{return}}async function je(e){let t=await ce(e),r=Y.basename(t),s=await xt(r);if(!s)return{path:t,verified:!1};let n=await wt(t);if(n.toLowerCase()!==s.toLowerCase())throw new Error(`Checksum mismatch for ${r}. Expected ${s}, got ${n}`);return{path:t,verified:!0,checksum:s}}function $e(){let e=process.platform,t=process.arch;try{let r=H[e][t],s=Y.join(C,r);if(!b.existsSync(s))throw new Error("Ytdlp binary not found. Please download it first.");return s}catch{return}}function O({url:e,options:t,ffmpegPath:r,withProgressTemplate:s,extra:n}){let o=k(t||{});return r&&o.push("--ffmpeg-location",r),s&&o.push("--progress-template",ae),n&&n.length>0&&o.push(...n),e&&o.push(e),o}var de=require("child_process");var W=class extends Error{constructor(t,r={}){super(t),this.name="YtDlpError",this.exitCode=r.exitCode,this.stdout=r.stdout,this.stderr=r.stderr,this.args=r.args,this.hint=r.hint}};var Pt="yt-dlp reported a missing JavaScript runtime. Install Node.js or a supported browser runtime for full YouTube support. See README troubleshooting for details.";function Ee(e){let t=e.toLowerCase();if(t.includes("javascript runtime")||t.includes("js runtime")||t.includes("node.js")||t.includes("nodejs")||t.includes("phantomjs")||t.includes("chromium")||t.includes("firefox"))return Pt}function Q(e,t,r){let s=F(e);s&&(t?.(s),r?.(s))}function X(e,t,r={}){r.debugPrintCommandLine&&console.error(`[ytdlp-nodejs] Command: ${e} ${t.join(" ")}`);let s=(0,de.spawn)(e,t,{shell:!1});return s.stdout.on("data",n=>{Q(Buffer.from(n).toString(),void 0,o=>s.emit("progress",o))}),s.stderr.on("data",n=>{Q(Buffer.from(n).toString(),void 0,o=>s.emit("progress",o))}),s}function h(e,t,r={}){return new Promise((s,n)=>{r.debugPrintCommandLine&&console.error(`[ytdlp-nodejs] Command: ${e} ${t.join(" ")}`);let o=(0,de.spawn)(e,t,{shell:!1}),i="",a="";r.passThrough&&o.stdout.pipe(r.passThrough),o.stdout.on("data",u=>{if(r.passThrough)return;let l=Buffer.from(u).toString();i+=l,r.onStdout?.(l),Q(l,r.onProgress)}),o.stderr.on("data",u=>{let l=Buffer.from(u).toString();a+=l,r.onStderr?.(l),Q(l,r.onProgress)}),o.on("close",u=>{if(u===0)s({stdout:i,stderr:a,exitCode:u});else{let l=Ee(a);n(new W(`yt-dlp exited with code ${u}: ${a}`,{exitCode:u??void 0,stdout:i,stderr:a,args:t,hint:l}))}}),o.on("error",u=>{n(new W(`Failed to start yt-dlp process: ${u.message}`,{args:t}))})})}function Be(e){return e.split(/\r?\n/).map(t=>t.trim()).filter(t=>t.length>0).filter(t=>!t.includes("~ytdlp-progress-"))}var vt=[".jpg",".jpeg",".png",".webp",".gif"],St=[".vtt",".srt",".ass",".ssa",".sub",".lrc"];function Ne(e){let t=[],r=[],s=[];for(let n of e){let o=n.toLowerCase();vt.some(i=>o.endsWith(i))?r.push(n):St.some(i=>o.endsWith(i))?s.push(n):t.push(n)}return{filePaths:t,thumbnailPaths:r,subtitlePaths:s}}function _e(e){return O({url:e.url,options:e.options,ffmpegPath:e.ffmpegPath,withProgressTemplate:e.withProgressTemplate,extra:e.extra})}function Le(e){let t=$(e);return t.push("--print","after_move:filepath"),t}function kt(e,t){if(!e.stdout)return;let r=[],s="";e.stdout.on("data",n=>{s+=n.toString();let o=s.split(/\r?\n/);s=o.pop()||"";for(let i of o){let a=i.trim();!a||a.includes("~ytdlp-progress-")||r.push(a)}}),e.on("close",()=>{let n=s.trim();if(n&&!n.includes("~ytdlp-progress-")&&r.push(n),r.length>0){let o=Ne(r);e.emit("paths",o)}t?.(r)})}function Ft(e,t){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return X(e.binaryPath,t)}async function Ct(e,t,r,s){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return(await h(e.binaryPath,t,{onStdout:r,onStderr:r,passThrough:s})).stdout}async function At(e,t,r){let{format:s,onProgress:n,onPaths:o,...i}=r||{},a=Le(s),u=_e({url:t,options:i,ffmpegPath:e.ffmpegPath,withProgressTemplate:!!n,extra:a}),l=await Ct(e,u,f=>{let p=F(f);p&&n?.(p)}),c=Be(l);return o?.(c),{output:l,paths:c}}function Me(e,t,r){let{format:s,onPaths:n,...o}=r||{},i=Le(s),a=_e({url:t,options:o,ffmpegPath:e.ffmpegPath,withProgressTemplate:!0,extra:i}),u=Ft(e,a);return kt(u,n),u}async function Ve(e,t,r){let s=await At(e,t,r),{filePaths:n,thumbnailPaths:o,subtitlePaths:i}=Ne(s.paths);return{output:s.output,filePaths:n,thumbnailPaths:o,subtitlePaths:i}}var pe=require("stream");async function Dt(e,t,r,s){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return(await h(e.binaryPath,t,{passThrough:s,onProgress:r})).stdout}function Ue(e,t,r){let{format:s,onProgress:n,...o}=r||{},i=O({url:t,options:o,ffmpegPath:e.ffmpegPath,withProgressTemplate:!!n,extra:[...$(s),"-o","-"]}),a=new pe.PassThrough;return{promise:Dt(e,i,n,a),pipe:(l,c)=>a.pipe(l,c),pipeAsync:(l,c)=>new Promise((f,p)=>{let v=a.pipe(l,c);l.on("finish",()=>f(v)),l.on("error",p)})}}async function Ye(e,t,r){let{format:s,filename:n,metadata:o,onProgress:i,...a}=r||{},u="";if(!n)try{u=(await h(e.binaryPath,["--print","%(title)s","--no-download",t])).stdout.trim()}catch{}let l=new pe.PassThrough,c=[];l.on("data",z=>{c.push(Buffer.from(z))});let f=O({url:t,options:a,ffmpegPath:e.ffmpegPath,withProgressTemplate:!!i,extra:[...$(s),"-o","-"]});if(!e.binaryPath)throw new Error("Ytdlp binary not found");await h(e.binaryPath,f,{onStderr:z=>{if(i){let we=F(z);we&&i(we)}},passThrough:l});let p=Fe(a)||oe(s)||"video/mp4",S={"video/mp4":"mp4","video/webm":"webm","video/mkv":"mkv","audio/mp3":"mp3","audio/mpeg":"mp3","audio/m4a":"m4a","audio/aac":"aac","audio/flac":"flac","audio/wav":"wav","audio/ogg":"ogg","audio/opus":"opus"}[p]||p.split("/")[1]||"mp4",D=u?`${u}.${S}`:"",be={name:n||D||"download",type:p,size:Buffer.concat(c).length,...o};return new File([new Uint8Array(Buffer.concat(c))],be.name,{type:be.type})}function me(e){let t=e.trim();if(!t)throw new Error("Empty JSON output from yt-dlp.");return JSON.parse(t)}async function I(e,t){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return(await h(e.binaryPath,t)).stdout}async function We(e,t,r){let s=["--dump-single-json","--quiet",...k({flatPlaylist:!0,...r}),t],n=await I(e,s);return me(n)}async function Je(e,t,r){let s=["--dump-single-json","--quiet",...k({flatPlaylist:!0,...r}),t],n=await I(e,s),o=me(n),i=o.formats||[];return{source:"json",info:o,formats:i}}async function ze(e,t,r){let s=["--get-url",...k(r||{}),t],n=await I(e,s);return String(n).split(/\r?\n/).map(o=>o.trim()).filter(o=>o.length>0)}async function Ke(e,t){let s=await I(e,["--print","thumbnails_table","--print","playlist:thumbnails_table","--quiet",t]);return ne(s)}async function qe(e,t){return await I(e,["--print","title",t])}async function Ge(e){return(await I(e,["--version"])).trim()}async function He(e,t,r){let s=["--print","urls",...k({flatPlaylist:!0,...r}),t],n=await I(e,s);return String(n).split(`
`)}var N=class{constructor(t){if(this.binaryPath=t?.binaryPath||$e()||"",this.ffmpegPath=t?.ffmpegPath||G(),(!this.binaryPath||!J.existsSync(this.binaryPath))&&console.error(new Error("yt-dlp binary not found. Please install yt-dlp or specify correct binaryPath in options.")),this.ffmpegPath&&!J.existsSync(this.ffmpegPath)&&console.error(new Error(`FFmpeg binary not found at: ${this.ffmpegPath}. Please install FFmpeg or specify correct ffmpegPath.`)),process.platform!=="win32"&&this.binaryPath&&this.binaryPath.startsWith(C))try{J.chmodSync(this.binaryPath,493)}catch{}}getDownloadContext(){return{binaryPath:this.binaryPath,ffmpegPath:this.ffmpegPath}}getStreamContext(){return{binaryPath:this.binaryPath,ffmpegPath:this.ffmpegPath}}getInfoContext(){return{binaryPath:this.binaryPath}}async checkInstallationAsync(t){return new Promise((r,s)=>{if(t?.ffmpeg&&!this.ffmpegPath)return s(new Error("FFmpeg path is not set"));let n=(0,B.spawn)(this.binaryPath,["--version"]),o=!1,i=!t?.ffmpeg;n.on("error",()=>o=!1),n.on("exit",a=>{if(o=a===0,t?.ffmpeg){let u=(0,B.spawn)(this.ffmpegPath,["-version"]);u.on("error",()=>i=!1),u.on("exit",l=>{i=l===0,r(o&&i)})}else r(o)})})}checkInstallation(t){if(t?.ffmpeg&&!this.ffmpegPath)throw new Error("FFmpeg path is not set");let r=(0,B.spawnSync)(this.binaryPath,["--version"],{stdio:"ignore"}),s=t?.ffmpeg?(0,B.spawnSync)(this.ffmpegPath,["-version"],{stdio:"ignore"}):{status:0};return r.status===0&&s.status===0}async execAsync(t,r){let s=this.buildArgs(t,r||{}),n=o=>{if(r?.onData?.(o),r?.onProgress){let i=F(o);i&&r.onProgress?.(i)}};return this._executeAsync(s,n)}exec(t,r){let s=this.buildArgs(t,r||{},!0);return this._execute(s)}_execute(t){return X(this.binaryPath,t)}async _executeAsync(t,r){if(!this.binaryPath)throw new Error("Ytdlp binary not found");return(await h(this.binaryPath,t,{onStdout:r,onStderr:r})).stdout}buildArgs(t,r,s,n){return O({url:t,options:r,ffmpegPath:this.ffmpegPath,withProgressTemplate:s,extra:n})}download(t,r){return Me(this.getDownloadContext(),t,r)}async downloadAsync(t,r){return Ve(this.getDownloadContext(),t,r)}stream(t,r){return Ue(this.getStreamContext(),t,r)}async getInfoAsync(t,r){return We(this.getInfoContext(),t,r)}async downloadAudio(t,r="mp3",s){let n=["aac","flac","mp3","m4a","opus","vorbis","wav","alac"];if(!n.includes(r))throw new Error(`Invalid audio format: ${r}. Supported: ${n.join(", ")}`);return this.downloadAsync(t,{...s,extractAudio:!0,audioFormat:r})}async downloadVideo(t,r="best",s){let n=["best","2160p","1440p","1080p","720p","480p","360p","240p","144p","highest","lowest"];if(!n.includes(r))throw new Error(`Invalid video quality: ${r}. Supported: ${n.join(", ")}`);let o=r==="best"?"bestvideo+bestaudio/best":`bestvideo[height<=${parseInt(r)||1080}]+bestaudio/best[height<=${parseInt(r)||1080}]`;return this.downloadAsync(t,{...s,format:o})}async getSubtitles(t,r){return(await this.downloadAsync(t,{...r,listSubs:!0,skipDownload:!0})).output?[]:[]}async getComments(t,r=20,s){let n=await this.downloadAsync(t,{...s,writeComments:!0,dumpSingleJson:!0,skipDownload:!0,extractorArgs:{youtube:[`max_comments=${r}`,"player_skip=webpage"]}});try{return JSON.parse(n.output).comments||[]}catch{return[]}}async getDirectUrlsAsync(t,r){return ze(this.getInfoContext(),t,r)}async getFormatsAsync(t,r){return Je(this.getInfoContext(),t,r)}async getThumbnailsAsync(t){return Ke(this.getInfoContext(),t)}async getTitleAsync(t){return qe(this.getInfoContext(),t)}async getVersionAsync(){return Ge(this.getInfoContext())}async downloadFFmpeg(){return Ie()}async getFileAsync(t,r){return Ye(this.getStreamContext(),t,r)}async getUrlsAsync(t,r){return He(this.getInfoContext(),t,r)}async updateYtDlpAsync(t){if(t?.preferBuiltIn!==!1&&this.binaryPath)try{await h(this.binaryPath,["--update"]);let a=await this.getVersionAsync().catch(()=>{});return{method:"built-in",binaryPath:this.binaryPath,version:a}}catch{}let s=t?.outDir||(this.binaryPath?Qe.default.dirname(this.binaryPath):void 0);if(t?.verifyChecksum!==!1){let a=await je(s),u=await h(a.path,["--version"]).then(l=>l.stdout.trim()).catch(()=>{});return{method:"download",binaryPath:a.path,version:u,verified:a.verified}}let o=await ce(s),i=await h(o,["--version"]).then(a=>a.stdout.trim()).catch(()=>{});return{method:"download",binaryPath:o,version:i,verified:!1}}};var _=m(require("fs")),Z=m(require("os")),R=m(require("path")),ge={subtitles:{},sponsorblock:{}};function Ot(){return process.env.YTDLP_NODEJS_CONFIG_DIR?process.env.YTDLP_NODEJS_CONFIG_DIR:process.platform==="win32"?process.env.APPDATA||R.default.join(Z.default.homedir(),"AppData","Roaming"):process.platform==="darwin"?R.default.join(Z.default.homedir(),"Library","Application Support"):process.env.XDG_CONFIG_HOME||R.default.join(Z.default.homedir(),".config")}async function Xe(){let e=Ot();return process.env.YTDLP_NODEJS_CONFIG_DIR?R.default.join(e,"config.json"):R.default.join(e,"ytdlp-nodejs","config.json")}function he(e,t){let r={...e};for(let[s,n]of Object.entries(t))n&&typeof n=="object"&&!Array.isArray(n)&&typeof r[s]=="object"&&r[s]!==null?r[s]=he(r[s],n):n!==void 0&&(r[s]=n);return r}async function P(){let e=await Xe();if(!_.default.existsSync(e))return{...ge};try{let t=_.default.readFileSync(e,"utf8"),r=JSON.parse(t);return he(ge,r)}catch{return{...ge}}}async function It(e){let t=await Xe(),r=R.default.dirname(t);_.default.existsSync(r)||_.default.mkdirSync(r,{recursive:!0}),_.default.writeFileSync(t,JSON.stringify(e,null,2))}async function ee(e){let t=await P(),r=he(t,e);return await It(r),r}var Ze=m(require("readline"));function w(){let e=Ze.default.createInterface({input:process.stdin,output:process.stdout});return{ask:r=>new Promise(s=>e.question(r,s)),close:()=>e.close()}}async function g(e,t,r){let s=r?`${t} (${r}): `:`${t}: `,n=(await e(s)).trim();return!n&&r!==void 0?r:n.toLowerCase()==="q"?null:n}async function A(e,t,r){let n=(await e(`${t}${r===void 0?" (y/n): ":r?" (Y/n): ":" (y/N): "}`)).trim().toLowerCase();return!n&&r!==void 0?r:n==="q"?null:n==="y"||n==="yes"?!0:n==="n"||n==="no"?!1:r??!1}async function T(e,t,r,s){console.log(t),r.forEach((i,a)=>{console.log(` ${a+1}) ${i.label}`)});let n=s?r.findIndex(i=>i.value===s)+1:0,o=n?`Select (1-${r.length}) [${n}]: `:`Select (1-${r.length}): `;for(;;){let i=(await e(o)).trim();if(i.toLowerCase()==="q")return null;if(!i&&n)return r[n-1].value;let a=Number(i);if(Number.isInteger(a)&&a>=1&&a<=r.length)return r[a-1].value}}async function ye(e,t,r,s){console.log(t),r.forEach((i,a)=>{console.log(` ${a+1}) ${i.label}`)});let o=`Select comma-separated numbers${s&&s.length>0?` [${s.join(",")}]`:""}: `;for(;;){let i=(await e(o)).trim();if(i.toLowerCase()==="q")return null;if(!i&&s)return s;let a=i.split(",").map(l=>Number(l.trim())).filter(l=>Number.isInteger(l));if(a.length===0)continue;let u=Array.from(new Set(a));if(!u.some(l=>l<1||l>r.length))return u.map(l=>r[l-1].value)}}async function et(e,t,r){let{ask:s,close:n}=w();try{let o=await g(s,"Video URL");if(!o)return;let i;if(r)i={filter:"audioonly",type:"mp3",quality:5};else{let f=await T(s,"Format",[{value:"best",label:"Best available"},{value:"worst",label:"Worst available"},{value:"audio-only",label:"Audio only"},{value:"picker",label:"Pick from list"},{value:"custom",label:"Custom format string"}]);if(!f)return;if((f==="best"||f==="worst")&&(i=f),f==="audio-only"&&(i={filter:"audioonly",type:"mp3",quality:5}),f==="custom"){let p=await g(s,"yt-dlp format string");if(!p)return;i=String(p)}if(f==="picker"){let p=await e.getFormatsAsync(String(o)),v=[];p.source==="json"&&p.formats&&(v=p.formats.map(D=>({value:D.format_id,label:`${D.format_id} ${D.ext||""} ${D.resolution||""} ${D.format_note||""}`.trim()})));let S=await T(s,"Pick a format",v);if(!S)return;i=String(S)}}let a={};j(a,t);let u=await A(s,"Return output file paths after download?",!0);if(u===null)return;let l=await A(s,"Show progress",!0);if(l===null)return;let c={...a,format:i,onProgress:l?K("Downloading"):void 0,printPaths:!!u,onPaths:u?f=>{l&&process.stdout.write(`
`),console.log(f.join(`
`))}:void 0};await e.downloadAsync(String(o),c),!u&&l&&process.stdout.write(`
`)}finally{n()}}async function Rt(e){let{ask:t,close:r}=w();try{let s=await g(t,"Video URL");if(!s)return;let n=await e.getInfoAsync(String(s));console.log(JSON.stringify(n,null,2))}finally{r()}}async function Tt(e){let{ask:t,close:r}=w();try{let s=await g(t,"Video URL");if(!s)return;let n=await e.getFormatsAsync(String(s));if(n.source==="json"&&n.formats){let o=n.formats.map(i=>({formatId:i.format_id,extension:i.ext||"",resolution:i.resolution||"",note:i.format_note||"",raw:""}));console.log(L(o))}else console.log("No formats found")}finally{r()}}async function jt(e){let{ask:t,close:r}=w();try{let s=await g(t,"Video URL");if(!s)return;let n=await e.getDirectUrlsAsync(String(s));console.log(n.join(`
`))}finally{r()}}async function $t(e,t){let{ask:r,close:s}=w();try{let n=await g(r,"Video URL");if(!n)return;let o=[];try{let f=await e.getInfoAsync(String(n));o=[...Object.keys(f.subtitles||{}),...Object.keys(f.automatic_captions||{})]}catch{o=[]}let i=await ye(r,"Subtitle languages",o.length>0?o.map(f=>({value:f,label:f})):[{value:"en",label:"en"}]);if(!i)return;let a=await T(r,"Subtitle format",[{value:"vtt",label:"vtt"},{value:"srt",label:"srt"},{value:"ass",label:"ass"}]);if(!a)return;let u=await A(r,"Embed subtitles",t.subtitles?.embed??!1);if(u===null)return;let l=await A(r,"Include auto subtitles",t.subtitles?.auto??!1);if(l===null)return;let c={writeSubs:!0,writeAutoSubs:!!l,subLangs:i,subFormat:String(a),embedSubs:!!u,skipDownload:!0};j(c,t),await e.execAsync(String(n),c)}finally{s()}}async function Et(e,t){let{ask:r,close:s}=w();try{let n=await g(r,"Video URL");if(!n)return;let o=await ye(r,"SponsorBlock categories",[{value:"sponsor",label:"sponsor"},{value:"intro",label:"intro"},{value:"outro",label:"outro"},{value:"selfpromo",label:"selfpromo"},{value:"interaction",label:"interaction"},{value:"preview",label:"preview"},{value:"filler",label:"filler"}],t.sponsorblock?.categories);if(!o)return;let i=await T(r,"SponsorBlock mode",[{value:"mark",label:"Mark as chapters"},{value:"remove",label:"Remove/cut"}],t.sponsorblock?.mode??"remove");if(!i)return;let a={};j(a,t),i==="mark"&&(a.sponsorblockMark=o),i==="remove"&&(a.sponsorblockRemove=o),await e.downloadAsync(String(n),a)}finally{s()}}async function Bt(e,t){let{ask:r,close:s}=w();try{let n=await g(r,"Video URL");if(!n)return;let o=await g(r,"Section range (e.g. *10:15-20:00 or chapter:Intro)");if(!o)return;let i=await A(r,"Split chapters",!1);if(i===null)return;let a={downloadSections:String(o),splitChapters:!!i};j(a,t),await e.downloadAsync(String(n),a)}finally{s()}}async function Nt(e){let t=await e.updateYtDlpAsync();console.log(`Updated via ${t.method}. Binary: ${t.binaryPath}${t.version?` (version ${t.version})`:""}`)}async function _t(e){let{ask:t,close:r}=w();try{let s=await g(t,"Default download directory",e.downloadDir??"");if(s===null)return;let n=await g(t,"Default format",e.defaultFormat??"");if(n===null)return;let o=await g(t,"Subtitle languages (comma-separated)",(e.subtitles?.languages||[]).join(","));if(o===null)return;let i=await g(t,"Subtitle format",e.subtitles?.format??"vtt");if(i===null)return;let a=await A(t,"Embed subtitles",e.subtitles?.embed??!1);if(a===null)return;let u=await g(t,"SponsorBlock categories (comma-separated)",(e.sponsorblock?.categories||[]).join(","));if(u===null)return;let l=await T(t,"SponsorBlock mode",[{value:"mark",label:"Mark as chapters"},{value:"remove",label:"Remove/cut"}],e.sponsorblock?.mode??"remove");if(!l)return;let c=await g(t,"Proxy",e.proxy??"");if(c===null)return;let f=await g(t,"Cookies file path",e.cookiesPath??"");if(f===null)return;let p=await g(t,"Concurrent fragments",e.concurrency?.toString()??"");if(p===null)return;let v=await A(t,"Verbose logging",e.verbose??!1);if(v===null)return;await ee({downloadDir:String(s)||void 0,defaultFormat:String(n)||void 0,subtitles:{languages:String(o).split(",").map(S=>S.trim()).filter(Boolean),format:String(i)||void 0,embed:!!a},sponsorblock:{categories:String(u).split(",").map(S=>S.trim()).filter(Boolean),mode:l},proxy:String(c)||void 0,cookiesPath:String(f)||void 0,concurrency:Number(p)||void 0,verbose:!!v})}finally{r()}}async function tt(){let e=new N,t=await P();console.log("ytdlp-nodejs");let{ask:r,close:s}=w();try{let n=await T(r,"Choose an action",[{value:"download",label:"Download video"},{value:"audio",label:"Download audio only"},{value:"info",label:"Get info (JSON summary)"},{value:"formats",label:"List formats"},{value:"urls",label:"Get direct URLs"},{value:"subs",label:"Subtitles flow"},{value:"sponsorblock",label:"SponsorBlock flow"},{value:"sections",label:"Download sections/time range"},{value:"update",label:"Update yt-dlp"},{value:"settings",label:"Settings"}]);if(!n)return;switch(n){case"download":await et(e,t);break;case"audio":await et(e,t,!0);break;case"info":await Rt(e);break;case"formats":await Tt(e);break;case"urls":await jt(e);break;case"subs":await $t(e,t);break;case"sponsorblock":await Et(e,t);break;case"sections":await Bt(e,t);break;case"update":await Nt(e);break;case"settings":await _t(t);break;default:break}}finally{s()}console.log("Done")}function Lt(e){if(e.source==="json"){let t=e.formats.map(r=>({formatId:r.format_id,extension:r.ext||"",resolution:r.resolution||"",note:r.format_note||"",raw:""}));console.log(L(t))}else console.log(L(e.table.rows))}async function rt(e,t,r){let s=new N;if(e==="download"){let n=t[0];if(!n){y();return}let o=await P(),i=M(r,o);re(i,r,o),se(i,r,o);let a=Se(r,o),u={...i,format:a,onProgress:r.verbose?K("Downloading"):void 0};u.printPaths=!!r.printPaths,r.printPaths&&(u.onPaths=l=>console.log(l.join(`
`))),await s.downloadAsync(String(n),u);return}if(e==="info"){let n=t[0];if(!n){y();return}let o=await s.getInfoAsync(String(n));console.log(JSON.stringify(o,null,2));return}if(e==="formats"){let n=t[0];if(!n){y();return}let o=await s.getFormatsAsync(String(n));Lt(o);return}if(e==="urls"){let n=t[0];if(!n){y();return}let o=await s.getDirectUrlsAsync(String(n));console.log(o.join(`
`));return}if(e==="subs"){let n=t[0];if(!n){y();return}let o=await P(),i=M(r,o);re(i,{...r,writeSubs:!0,writeAutoSubs:r.auto,embedSubs:r.embed},o),i.skipDownload=!0,await s.execAsync(String(n),i);return}if(e==="sponsorblock"){let n=t[0];if(!n){y();return}let o=await P(),i=M(r,o);se(i,{sponsorblockCategories:r.categories||r.sponsorblockCategories,sponsorblockMode:r.mode||r.sponsorblockMode},o),await s.downloadAsync(String(n),i);return}if(e==="sections"){let n=t[0];if(!n){y();return}let o=r.range;if(!o){y();return}let i=await P(),a=M(r,i);a.downloadSections=String(o),a.splitChapters=!!r.splitChapters,await s.downloadAsync(String(n),a);return}if(e==="update"){let n=await s.updateYtDlpAsync();console.log(`Updated via ${n.method}. Binary: ${n.binaryPath}${n.version?` (version ${n.version})`:""}`);return}if(e==="config"){if(r.set){let[o,i]=String(r.set).split("=");if(!o){console.error("Invalid config pair.");return}await ee({[o]:i})}let n=await P();console.log(JSON.stringify(n,null,2));return}y()}async function Mt(){let{command:e,positionals:t,options:r}=ve(process.argv.slice(2));if(!e){await tt();return}if(r.help||e==="help"){y();return}await rt(e,t,r)}Mt().catch(e=>{console.error(e),process.exit(1)});
"use strict";var k=Object.create;var w=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var C=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var D=(o,t,r,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of R(t))!A.call(o,n)&&n!==r&&w(o,n,{get:()=>t[n],enumerable:!(e=E(t,n))||e.enumerable});return o};var d=(o,t,r)=>(r=o!=null?k(C(o)):{},D(t||!o||!o.__esModule?w(r,"default",{value:o,enumerable:!0}):r,o));var c=d(require("fs")),g=d(require("path"));var N=d(require("https")),O=d(require("http")),m=require("url"),a=d(require("fs"));function y(o,t={}){return new Promise((r,e)=>{let s=(new m.URL(o).protocol==="https:"?N:O).get(o,t,i=>{if(i.statusCode>=300&&i.statusCode<400&&i.headers.location){let p=new m.URL(i.headers.location,o).toString();y(p,t).then(r).catch(e);return}r(i)});s.on("error",e),s.setTimeout(3e4,()=>{s.destroy(),e(new Error("Request timed out"))})})}async function x(o,t){try{let r=a.createWriteStream(t),e=await y(o);if(e.statusCode!==200)throw r.close(),a.unlinkSync(t),new Error(`Failed to download file: ${e.statusCode} ${e.statusMessage}`);let n=parseInt(e.headers["content-length"]||"0",10),f=0;return e.on("data",s=>{f+=s.length;let i=f/n*100;process.stdout.write(`Progress: ${Math.round(i)}%\r`)}),e.pipe(r),new Promise((s,i)=>{r.on("finish",()=>{r.close(),console.log(`
Download complete!`),s()}),r.on("error",p=>{r.close(),a.unlinkSync(t),i(p)}),e.on("error",p=>{r.close(),a.unlinkSync(t),i(p)})})}catch(r){throw a.existsSync(t)&&a.unlinkSync(t),r}}var S=d(require("fs")),l=d(require("path"));function b(o){let t=o;for(;;){if(S.existsSync(l.join(t,"package.json")))return t;let r=l.dirname(t);if(r===t)return o;t=r}}var P=b(__dirname),_=l.join(P,"bin"),T=l.join(P,"package.json");var F="https://github.com/yt-dlp/yt-dlp/releases/latest/download",u={win32:{x64:"yt-dlp.exe",ia32:"yt-dlp_x86.exe"},linux:{x64:"yt-dlp",armv7l:"yt-dlp_linux_armv7l",aarch64:"yt-dlp_linux_aarch64",arm64:"yt-dlp"},darwin:{x64:"yt-dlp_macos",arm64:"yt-dlp_macos"},android:{arm64:"yt-dlp"}};function I(){let o=process.platform,t=process.arch;if(!u[o]||!u[o][t])throw new Error(`No yt-dlp build available for ${o} ${t}`);return u[o][t]}async function $(o){let t=o||_,r=I(),e=`${F}/${r}`,n=g.join(t,r);if(c.existsSync(n))return n;console.log("Downloading yt-dlp...",e),c.existsSync(t)||c.mkdirSync(t,{recursive:!0});try{await x(e,n),console.log(`yt-dlp downloaded successfully to: ${n}`);try{c.chmodSync(n,493)}catch{console.log("Error while chmod")}return n}catch(s){throw console.error(`Download failed: ${s}`),s}}$().catch(o=>{console.error("Failed to download yt-dlp:",o),process.exit(1)});
+644
-39

@@ -1,293 +0,634 @@

import * as child_process from 'child_process';
import { ChildProcess } from 'child_process';
/**
* yt-dlp command-line options mapped to TypeScript.
* @see https://github.com/yt-dlp/yt-dlp#usage-and-options
*/
interface ArgsOptions {
/** Print help text and exit. Maps to `--help`. */
printHelp?: boolean;
/** Print program version and exit. Maps to `--version`. */
printVersion?: boolean;
/** Update yt-dlp to the latest version. Maps to `--update`. */
update?: boolean;
/** Do not check for updates. Maps to `--no-update`. */
noUpdate?: boolean;
/** Update to a specific version. Maps to `--update-to TAG`. */
updateTo?: string;
/** Continue on download errors. Maps to `--ignore-errors`. */
ignoreErrors?: boolean;
/** Continue with next video after error. Maps to `--no-abort-on-error`. */
noAbortOnError?: boolean;
/** Abort on download error. Maps to `--abort-on-error`. */
abortOnError?: boolean;
/** Display current browser user-agent. Maps to `--dump-user-agent`. */
dumpUserAgent?: boolean;
/** List all supported extractors. Maps to `--list-extractors`. */
listExtractors?: boolean;
/** Output descriptions of all extractors. Maps to `--extractor-descriptions`. */
extractorDescriptions?: boolean;
/** Use only specific extractors. Maps to `--use-extractors NAMES`. */
useExtractors?: string[];
/** Use this prefix for search queries. Maps to `--default-search PREFIX`. */
defaultSearch?: string;
/** Don't read configuration files. Maps to `--ignore-config`. */
ignoreConfig?: boolean;
/** Don't load config from default locations. Maps to `--no-config-location`. */
noConfigLocations?: boolean;
/** Location of the main config file. Maps to `--config-locations PATH`. */
configLocations?: string[];
/** Directories to load plugins from. Maps to `--plugin-dirs PATH`. */
pluginDirs?: string[];
/** Disable loading plugins. Maps to `--no-plugin-dirs`. */
noPluginDirs?: boolean;
/** Don't extract videos of a playlist. Maps to `--flat-playlist`. */
flatPlaylist?: boolean;
/** Extract videos of a playlist. Maps to `--no-flat-playlist`. */
noFlatPlaylist?: boolean;
/** Download livestreams from the start. Maps to `--live-from-start`. */
liveFromStart?: boolean;
/** Don't download from the start. Maps to `--no-live-from-start`. */
noLiveFromStart?: boolean;
/** Wait seconds for a video to become available. Maps to `--wait-for-video SEC`. */
waitForVideo?: number;
/** Don't wait for video. Maps to `--no-wait-for-video`. */
noWaitForVideo?: boolean;
/** Mark videos watched on YouTube. Maps to `--mark-watched`. */
markWatched?: boolean;
/** Don't mark videos watched. Maps to `--no-mark-watched`. */
noMarkWatched?: boolean;
/** Color output (always, never, auto, no_color). Maps to `--color WHEN`. */
color?: string;
/** Options to adjust behavior. Maps to `--compat-options OPTS`. */
compatOptions?: string[];
/** Command aliases. Maps to `--alias ALIAS CMD`. */
aliases?: string[];
/**
* JavaScript runtime for extractors requiring JS execution.
* Supported values: 'deno', 'node', 'phantomjs', etc.
* Maps to `--js-runtime RUNTIME`.
* @see https://github.com/yt-dlp/yt-dlp/wiki/EJS
*/
jsRuntime?: string;
/** Use the specified HTTP/HTTPS/SOCKS proxy. Maps to `--proxy URL`. */
proxy?: string;
/** Time to wait before giving up (seconds). Maps to `--socket-timeout SEC`. */
socketTimeout?: number;
/** Client-side IP address to bind to. Maps to `--source-address IP`. */
sourceAddress?: string;
/** Make all connections via IPv4. Maps to `--force-ipv4`. */
forceIpv4?: boolean;
/** Make all connections via IPv6. Maps to `--force-ipv6`. */
forceIpv6?: boolean;
/** Client to impersonate for requests. Maps to `--impersonate CLIENT`. */
impersonate?: string[];
/** List available clients to impersonate. Maps to `--list-impersonate-targets`. */
listImpersonateTargets?: boolean;
/** Enable file:// URLs. Maps to `--enable-file-urls`. */
enableFileUrls?: boolean;
/** Proxy for geo verification. Maps to `--geo-verification-proxy URL`. */
geoVerificationProxy?: string;
/** How to fake X-Forwarded-For header. Maps to `--xff VALUE`. */
xff?: string;
/** Bypass geographic restriction. Maps to `--geo-bypass`. */
geoBypass?: boolean;
/** Force bypass with a two-letter country code. Maps to `--geo-bypass-country CODE`. */
geoBypassCountry?: string;
/** Force bypass with an IP block. Maps to `--geo-bypass-ip-block IP_BLOCK`. */
geoBypassIpBlock?: string;
/** Playlist items to download (e.g., "1,3,5-7"). Maps to `--playlist-items ITEM_SPEC`. */
playlistItems?: string;
/** Don't download files smaller than SIZE. Maps to `--min-filesize SIZE`. */
minFilesize?: string;
/** Don't download files larger than SIZE. Maps to `--max-filesize SIZE`. */
maxFilesize?: string;
/** Download only videos uploaded on this date. Maps to `--date DATE`. */
date?: string;
/** Download only videos uploaded before this date. Maps to `--datebefore DATE`. */
dateBefore?: string;
/** Download only videos uploaded after this date. Maps to `--dateafter DATE`. */
dateAfter?: string;
/** Generic video filter. Maps to `--match-filter FILTER`. */
matchFilter?: string;
/** Do not use any --match-filter. Maps to `--no-match-filters`. */
noMatchFilters?: boolean;
/** Stop on filter match. Maps to `--break-match-filters FILTER`. */
breakMatchFilters?: string;
/** Do not --break-match-filters. Maps to `--no-break-match-filters`. */
noBreakMatchFilters?: boolean;
/** Download only the video for a single URL. Maps to `--no-playlist`. */
noPlaylist?: boolean;
/** Download the playlist if URL is a video and playlist. Maps to `--yes-playlist`. */
yesPlaylist?: boolean;
/** Download only videos suitable for the given age. Maps to `--age-limit YEARS`. */
ageLimit?: number;
/** Download only videos not in the archive. Maps to `--download-archive FILE`. */
downloadArchive?: string;
/** Do not use archive file. Maps to `--no-download-archive`. */
noDownloadArchive?: boolean;
/** Maximum number of files to download. Maps to `--max-downloads NUMBER`. */
maxDownloads?: number;
/** Stop if video is in archive. Maps to `--break-on-existing`. */
breakOnExisting?: boolean;
/** Do not stop on existing. Maps to `--no-break-on-existing`. */
noBreakOnExisting?: boolean;
/** Reset per input URL. Maps to `--break-per-input`. */
breakPerInput?: boolean;
/** Do not reset per input. Maps to `--no-break-per-input`. */
noBreakPerInput?: boolean;
/** Skip rest of playlist after N errors. Maps to `--skip-playlist-after-errors N`. */
skipPlaylistAfterErrors?: number;
/** Playlist video to start at (1-indexed). Maps to `--playlist-start NUMBER`. */
playlistStart?: number;
/** Playlist video to end at (1-indexed). Maps to `--playlist-end NUMBER`. */
playlistEnd?: number;
/** Download only videos whose title matches regex. Maps to `--match-title REGEX`. */
matchTitle?: string;
/** Skip videos whose title matches regex. Maps to `--reject-title REGEX`. */
rejectTitle?: string;
/** Download ads as well. Maps to `--include-ads`. */
includeAds?: boolean;
/** Stop on rejected title. Maps to `--break-on-reject`. */
breakOnReject?: boolean;
/**
* Number of fragments to download concurrently.
* Maps to `-N, --concurrent-fragments N`.
*/
concurrentFragments?: number;
/**
* Minimum download rate to avoid throttling (e.g., "100K").
* Re-extracts video data if download rate falls below this.
* Maps to `--throttled-rate RATE`.
*/
throttledRate?: string;
/** Number of retries for file access. Maps to `--file-access-retries RETRIES`. */
fileAccessRetries?: number;
retrySleep?: number;
/**
* Time to sleep between retries in seconds.
* Can be a number, "linear=START[:END[:STEP]]" or "exp=START[:END[:BASE]]".
* Use retrySleepType for type-specific sleep.
* Maps to `--retry-sleep [TYPE:]EXPR`.
*/
retrySleep?: number | string;
/**
* Type-specific retry sleep configuration.
* Keys: 'http', 'fragment', 'file_access', 'extractor'.
* Maps to `--retry-sleep TYPE:EXPR`.
*/
retrySleepByType?: {
[type: string]: string;
};
/** Delete fragments after download. Maps to `--no-keep-fragments`. */
noKeepFragments?: boolean;
/** Automatically resize the download buffer. Maps to `--resize-buffer`. */
resizeBuffer?: boolean;
/** Don't automatically resize buffer. Maps to `--no-resize-buffer`. */
noResizeBuffer?: boolean;
/** Process playlist entries as received. Maps to `--lazy-playlist`. */
lazyPlaylist?: boolean;
/** Parse entire playlist before downloading. Maps to `--no-lazy-playlist`. */
noLazyPlaylist?: boolean;
/** Don't use mpegts container for HLS. Maps to `--no-hls-use-mpegts`. */
noHlsUseMpegts?: boolean;
/**
* Download only matching sections (time range or chapters).
* Examples: "*10:15-inf", "intro", "*from-url".
* Maps to `--download-sections REGEX`.
*/
downloadSections?: string;
/**
* External downloader to use.
* Supports: native, aria2c, axel, curl, ffmpeg, httpie, wget.
* Maps to `--downloader [PROTO:]NAME`.
*/
downloader?: string;
/** Arguments to pass to external downloader. Maps to `--downloader-args NAME:ARGS`. */
downloaderArgs?: string;
playlistStart?: number;
playlistEnd?: number;
matchTitle?: string;
rejectTitle?: string;
includeAds?: boolean;
limitRate?: string;
breakOnReject?: boolean;
noDownload?: boolean;
playlistReverse?: boolean;
playlistRandom?: boolean;
xattrSetFilesize?: boolean;
hlsSplitDiscontinuity?: boolean;
geoBypass?: boolean;
geoBypassCountry?: string;
geoBypassIpBlock?: string;
batchFile?: string;
/** Number of retries (default 10). Maps to `-R, --retries RETRIES`. */
retries?: number;
/** Number of retries for a fragment. Maps to `--fragment-retries RETRIES`. */
fragmentRetries?: number;
/** Skip unavailable fragments. Maps to `--skip-unavailable-fragments`. */
skipUnavailableFragments?: boolean;
/** Abort download if a fragment is unavailable. Maps to `--abort-on-unavailable-fragments`. */
abortOnUnavailableFragment?: boolean;
/** Keep downloaded fragments on disk. Maps to `--keep-fragments`. */
keepFragments?: boolean;
/** Size of download buffer (e.g., "1024", "16K"). Maps to `--buffer-size SIZE`. */
bufferSize?: string;
/** Don't resume partial downloads. Maps to `--no-resume-dl`. */
noResumeDl?: boolean;
/** Force resume of partial downloads. Maps to `-c, --continue`. */
continueDownload?: boolean;
/** Do not resume partial downloads. Maps to `--no-continue`. */
noContinue?: boolean;
/** Maximum download rate (e.g., "50K", "4.2M"). Maps to `-r, --limit-rate RATE`. */
limitRate?: string;
/** Extract cookies from browser. Maps to `--cookies-from-browser BROWSER`. */
cookiesFromBrowser?: string;
/** Don't read cookies from files. Maps to `--no-cookies`. */
noCookies?: boolean;
/** Number of retries for known extractor errors. Maps to `--extractor-retries RETRIES`. */
extractorRetries?: number;
/** Process dynamic DASH manifests. Maps to `--allow-dynamic-mpd`. */
allowDynamicMpd?: boolean;
/** Use mpegts container for HLS. Maps to `--hls-use-mpegts`. */
hlsUseMpegts?: boolean;
/**
* Size of a chunk for chunk-based HTTP downloading.
* May help bypass throttling (experimental).
* Maps to `--http-chunk-size SIZE`.
*/
httpChunkSize?: string;
/** Skip download (useful with --print). Maps to `--no-download`. */
noDownload?: boolean;
/** Download playlist videos in reverse order. Maps to `--playlist-reverse`. */
playlistReverse?: boolean;
/** Download playlist videos in random order. Maps to `--playlist-random`. */
playlistRandom?: boolean;
/** Set xattr filesize. Maps to `--xattr-set-filesize`. */
xattrSetFilesize?: boolean;
/** Split HLS at discontinuities. Maps to `--hls-split-discontinuity`. */
hlsSplitDiscontinuity?: boolean;
/** File containing URLs to download. Maps to `-a, --batch-file FILE`. */
batchFile?: string;
/** Don't read batch file. Maps to `--no-batch-file`. */
noBatchFile?: boolean;
/** Limit filename length to N characters. Maps to `--trim-filenames LENGTH`. */
trimFileNames?: number;
/** Don't restrict characters in filenames. Maps to `--no-restrict-filenames`. */
noRestrictFilenames?: boolean;
/** Don't force Windows-safe filenames. Maps to `--no-windows-filenames`. */
noWindowsFilenames?: boolean;
/** Force resume of partially downloaded files (deprecated). */
continue?: boolean;
/** Write .part files. Maps to `--part`. */
part?: boolean;
/** Don't use .part files. Maps to `--no-part`. */
noPart?: boolean;
/** Use file modification time from server. Maps to `--mtime`. */
mtime?: boolean;
/** Don't use server mtime. Maps to `--no-mtime`. */
noMtime?: boolean;
/** Write video description to .description file. Maps to `--write-description`. */
writeDescription?: boolean;
/** Don't write description file. Maps to `--no-write-description`. */
noWriteDescription?: boolean;
/** Write video metadata to .info.json file. Maps to `--write-info-json`. */
writeInfoJson?: boolean;
/** Don't write info json. Maps to `--no-write-info-json`. */
noWriteInfoJson?: boolean;
/** Write playlist metadata files. Maps to `--write-playlist-metafiles`. */
writePlaylistMetafiles?: boolean;
/** Don't write playlist metadata. Maps to `--no-write-playlist-metafiles`. */
noWritePlaylistMetafiles?: boolean;
/** Remove some private fields from infojson. Maps to `--clean-info-json`. */
cleanInfoJson?: boolean;
/** Don't clean infojson. Maps to `--no-clean-info-json`. */
noCleanInfoJson?: boolean;
/** Write video comments to infojson. Maps to `--write-comments`. */
writeComments?: boolean;
/** Don't write comments. Maps to `--no-write-comments`. */
noWriteComments?: boolean;
/** JSON file with video metadata. Maps to `--load-info-json FILE`. */
loadInfoJson?: string;
/** File to read cookies from. Maps to `--cookies FILE`. */
cookies?: string;
/** Do not read cookies from browser. Maps to `--no-cookies-from-browser`. */
noCookiesFromBrowser?: boolean;
/** Location to store cached data. Maps to `--cache-dir DIR`. */
cacheDir?: string;
/** Disable caching. Maps to `--no-cache-dir`. */
noCacheDir?: boolean;
/** Delete all filesystem cache files. Maps to `--rm-cache-dir`. */
rmCacheDir?: boolean;
/**
* Paths for different file types.
* Maps to `-P, --paths [TYPES:]PATH`.
*/
paths?: {
[key: string]: string;
} | string;
/** Output filename template. Maps to `-o, --output TEMPLATE`. */
output?: string;
/** Placeholder for unavailable template. Maps to `--output-na-placeholder TEXT`. */
outputNaPlaceholder?: string;
/** Restrict filenames to ASCII. Maps to `--restrict-filenames`. */
restrictFilenames?: boolean;
/** Force filenames to be Windows-safe. Maps to `--windows-filenames`. */
windowsFilenames?: boolean;
/** Don't overwrite existing files. Maps to `--no-overwrites`. */
noOverwrites?: boolean;
/** Overwrite all video and metadata files. Maps to `--force-overwrites`. */
forceOverwrites?: boolean;
/** Don't overwrite the video. Maps to `--no-force-overwrites`. */
noForceOverwrites?: boolean;
/** Start autonumber from given value. Maps to `--autonumber-start NUMBER`. */
autonumberStart?: number;
/** Don't use .part files. Maps to `--no-part-files`. */
noPartFiles?: boolean;
noBatchFile?: boolean;
/** Write thumbnail image to disk. Maps to `--write-thumbnail`. */
writeThumbnail?: boolean;
/** Write all thumbnail formats to disk. Maps to `--write-all-thumbnails`. */
writeAllThumbnails?: boolean;
/** Don't write thumbnails. Maps to `--no-write-thumbnails`. */
noWriteThumbnails?: boolean;
/** Convert thumbnails to format. Maps to `--convert-thumbnails FORMAT`. */
convertThumbnails?: string;
/** Write internet shortcut file. Maps to `--write-link`. */
writeLink?: boolean;
/** Write .url Windows shortcut. Maps to `--write-url-link`. */
writeUrlLink?: boolean;
/** Write .webloc macOS shortcut. Maps to `--write-webloc-link`. */
writeWeblocLink?: boolean;
/** Write .lnk Windows shortcut. Maps to `--write-lnk-link`. */
writeLnkLink?: boolean;
/** Write .desktop Linux shortcut. Maps to `--write-desktop-link`. */
writeDesktopLink?: boolean;
/** Quiet mode, print only errors. Maps to `-q, --quiet`. */
quiet?: boolean;
/** Ignore warnings. Maps to `--no-warnings`. */
noWarnings?: boolean;
/** Simulate, don't download or write files. Maps to `-s, --simulate`. */
simulate?: boolean;
/** Don't simulate. Maps to `--no-simulate`. */
noSimulate?: boolean;
/** Ignore "no video formats" errors. Maps to `--ignore-no-formats-error`. */
ignoreNoFormatsError?: boolean;
/** Ignore EOF errors. Maps to `--ignore-eof-error`. */
ignoreEoFError?: boolean;
/** Don't ignore EOF errors. Maps to `--no-ignore-eof-error`. */
noIgnoreEoFError?: boolean;
/** Don't emit color codes. Maps to `--no-color`. */
noColor?: boolean;
/** Display HTTP traffic. Maps to `--print-traffic`. */
printTraffic?: boolean;
/** Display progress in console title. Maps to `--console-title`. */
consoleTitle?: boolean;
/** Print various debugging information. Maps to `-v, --verbose`. */
verbose?: boolean;
/** Activate quiet mode. Maps to `--no-quiet`. */
noQuiet?: boolean;
/** Don't ignore "no formats" errors. Maps to `--no-ignore-no-formats-error`. */
noIgnoreNoFormatsError?: boolean;
/** Don't display progress bar. Maps to `--no-progress`. */
noProgress?: boolean;
/** Display progress bar. Maps to `--progress`. */
progress?: boolean;
/** Simulate and print info as JSON (single video). Maps to `-J, --dump-single-json`. */
dumpSingleJson?: boolean;
/** Simulate and print info as JSON. Maps to `-j, --dump-json`. */
dumpJson?: boolean;
/** Print JSON (equivalent to -j). Maps to `--print-json`. */
printJson?: boolean;
/** Don't download video. Maps to `--skip-download`. */
skipDownload?: boolean;
/** Quiet mode, print given template. Maps to `-O, --print [WHEN:]TEMPLATE`. */
print?: string;
/** Print template to file. Maps to `--print-to-file [WHEN:]TEMPLATE FILE`. */
printToFile?: string;
/** Force write to archive. Maps to `--force-write-archive`. */
forceWriteArchive?: boolean;
/** Output progress on a new line. Maps to `--newline`. */
newline?: boolean;
/** Template for progress outputs. Maps to `--progress-template TEMPLATE`. */
progressTemplate?: string;
/** Time between progress updates in seconds. Maps to `--progress-delta SEC`. */
progressDelta?: number;
/** Print the yt-dlp command line. Maps to `--print-command-line`. */
debugPrintCommandLine?: boolean;
/** Write downloaded pages to files. Maps to `--write-pages`. */
writePages?: boolean;
/** Dump parsed web pages. Maps to `--dump-pages`. */
dumpPages?: boolean;
/** Force character encoding. Maps to `--encoding ENCODING`. */
encoding?: string;
/** Use an unencrypted connection. Maps to `--legacy-server-connect`. */
legacyServerConnect?: boolean;
/** Suppress HTTPS certificate validation. Maps to `--no-check-certificates`. */
noCheckCertificates?: boolean;
/** Use an unencrypted connection. Maps to `--prefer-insecure`. */
preferInsecure?: boolean;
/** Specify additional HTTP headers. Maps to `--add-header FIELD:VALUE`. */
addHeaders?: {
[key: string]: string;
};
/** Specify custom binary path. Maps to `--bin-path PATH`. */
binPath?: string;
/** Work around bidi issue. Maps to `--bidi-workaround`. */
bidiWorkaround?: boolean;
/** Seconds to sleep between requests. Maps to `--sleep-requests SEC`. */
sleepRequests?: number;
/** Seconds to sleep before each download. Maps to `--sleep-interval SEC`. */
sleepInterval?: number;
/** Max seconds to sleep. Maps to `--max-sleep-interval SEC`. */
maxSleepInterval?: number;
/** Seconds to sleep before subtitle download. Maps to `--sleep-subtitles SEC`. */
sleepSubtitles?: number;
/** Video format code. Maps to `-f, --format FORMAT`. */
format?: string;
/** Sort formats by given fields. Maps to `-S, --format-sort SORTORDER`. */
formatSort?: string[];
/** Force format sorting. Maps to `--format-sort-force`. */
formatSortForce?: boolean;
/** Don't force format sorting. Maps to `--no-format-sort-force`. */
noFormatSortForce?: boolean;
/** Preferred audio format (mp3, wav, etc.). Maps to `--audio-format FORMAT`. */
audioFormat?: string;
/** Preferred video format. Maps to `--video-format FORMAT`. */
videoFormat?: string;
/** Prefer free container formats. Maps to `--prefer-free-formats`. */
preferFreeFormats?: boolean;
/** Don't prefer free formats. Maps to `--no-prefer-free-formats`. */
noPreferFreeFormats?: boolean;
/** Force keyframes at cuts. Maps to `--yt-dlp-force-keyframes`. */
ytdlpForceKeyframes?: boolean;
/** Container for merging formats (mp4, mkv, etc.). Maps to `--merge-output-format FORMAT`. */
mergeOutputFormat?: string;
/** Merge multiple video streams. Maps to `--video-multistreams`. */
videoMultiStreams?: boolean;
/** Don't merge multiple video streams. Maps to `--no-video-multistreams`. */
noVideoMultiStreams?: boolean;
/** Merge multiple audio streams. Maps to `--audio-multistreams`. */
audioMultiStreams?: boolean;
/** Don't merge multiple audio streams. Maps to `--no-audio-multistreams`. */
noAudioMultiStreams?: boolean;
/** Check that formats are downloadable. Maps to `--check-formats`. */
checkFormats?: boolean;
/** Check all formats. Maps to `--check-all-formats`. */
checkAllFormats?: boolean;
/** Don't check formats. Maps to `--no-check-formats`. */
noCheckFormats?: boolean;
/** Write subtitle files. Maps to `--write-subs`. */
writeSubs?: boolean;
/** Write auto-generated subtitle files. Maps to `--write-auto-subs`. */
writeAutoSubs?: boolean;
/** Write all available subtitles. Maps to `--write-all-subs`. */
writeAllSubs?: boolean;
/** Don't write subtitle files. Maps to `--no-write-subs`. */
noWriteSubs?: boolean;
/** List available subtitles. Maps to `--list-subs`. */
listSubs?: boolean;
/** Subtitle format (srt, vtt, ass, etc.). Maps to `--sub-format FORMAT`. */
subFormat?: string;
/** Languages of subtitles to download. Maps to `--sub-langs LANGS`. */
subLangs?: string[];
/** Login username. Maps to `-u, --username USERNAME`. */
username?: string;
/** Login password. Maps to `-p, --password PASSWORD`. */
password?: string;
/** Two-factor auth code. Maps to `-2, --twofactor CODE`. */
twoFactor?: string;
/** Use .netrc authentication. Maps to `-n, --netrc`. */
netrc?: boolean;
/** Video password (vimeo, etc.). Maps to `--video-password PASSWORD`. */
videoPassword?: string;
/** Location of .netrc file. Maps to `--netrc-location PATH`. */
netrcLocation?: string;
/** Command to get netrc credentials. Maps to `--netrc-cmd COMMAND`. */
netrcCmd?: string;
apListMso?: boolean;
/** Client certificate file. Maps to `--client-certificate CERTFILE`. */
clientCertificate?: string;
/** Client certificate key file. Maps to `--client-certificate-key KEYFILE`. */
clientCertificateKey?: string;
/** Client certificate password. Maps to `--client-certificate-password PASSWORD`. */
clientCertificatePassword?: string;
/** List available MSOs. Maps to `--ap-list-mso`. */
apListMso?: boolean;
/** Adobe Pass MSO. Maps to `--ap-mso MSO`. */
apMso?: string;
/** Adobe Pass username. Maps to `--ap-username USERNAME`. */
apUsername?: string;
/** Adobe Pass password. Maps to `--ap-password PASSWORD`. */
apPassword?: string;
/** Extract and save audio. Maps to `-x, --extract-audio`. */
extractAudio?: boolean;
/** Audio quality (0-9 VBR or specific bitrate). Maps to `--audio-quality QUALITY`. */
audioQuality?: string;
/** Remux video to another container. Maps to `--remux-video FORMAT`. */
remuxVideo?: string;
/** Re-encode video to another format. Maps to `--recode-video FORMAT`. */
recodeVideo?: string;
/** Additional args for post processors. Maps to `--postprocessor-args NAME:ARGS`. */
postprocessorArgs?: {
[key: string]: string[];
};
/** Keep the original video. Maps to `-k, --keep-video`. */
keepVideo?: boolean;
/** Delete the original video. Maps to `--no-keep-video`. */
noKeepVideo?: boolean;
/** Overwrite post-processed files. Maps to `--post-overwrites`. */
postOverwrites?: boolean;
/** Don't overwrite post-processed files. Maps to `--no-post-overwrites`. */
noPostOverwrites?: boolean;
/** Embed subtitles in the video. Maps to `--embed-subs`. */
embedSubs?: boolean;
/** Don't embed subtitles. Maps to `--no-embed-subs`. */
noEmbedSubs?: boolean;
/** Embed thumbnail in the video. Maps to `--embed-thumbnail`. */
embedThumbnail?: boolean;
/** Don't embed thumbnail. Maps to `--no-embed-thumbnail`. */
noEmbedThumbnail?: boolean;
/** Embed metadata in the file. Maps to `--embed-metadata`. */
embedMetadata?: boolean;
/** Don't embed metadata. Maps to `--no-embed-metadata`. */
noEmbedMetadata?: boolean;
/** Embed chapters in the video. Maps to `--embed-chapters`. */
embedChapters?: boolean;
/** Don't embed chapters. Maps to `--no-embed-chapters`. */
noEmbedChapters?: boolean;
/** Embed info.json in video. Maps to `--embed-info-json`. */
embedInfoJson?: boolean;
/** Don't embed info.json. Maps to `--no-embed-info-json`. */
noEmbedInfoJson?: boolean;
/** Parse and modify metadata. Maps to `--parse-metadata FROM:TO`. */
parseMetadata?: {
[key: string]: string;
};
/** Replace text in a metadata field. Maps to `--replace-in-metadata FIELDS REGEX REPLACE`. */
replaceInMetadata?: {
[key: string]: [string, string];
};
/** Write extended attributes. Maps to `--xattrs`. */
xattrs?: boolean;
/** Concatenate playlist into a single file. Maps to `--concat-playlist POLICY`. */
concatPlaylist?: string;
/** Fix file problems (never, warn, detect_or_warn, force). Maps to `--fixup POLICY`. */
fixup?: string;
/** Location of FFmpeg binary. Maps to `--ffmpeg-location PATH`. */
ffmpegLocation?: string;
/** Execute command on file. Maps to `--exec CMD`. */
exec?: string;
/** Don't execute command. Maps to `--no-exec`. */
noExec?: boolean;
/** Convert subtitles to format. Maps to `--convert-subs FORMAT`. */
convertSubs?: string;
/** Split video by chapters. Maps to `--split-chapters`. */
splitChapters?: boolean;
/** Don't split by chapters. Maps to `--no-split-chapters`. */
noSplitChapters?: boolean;
/** Remove chapters matching regex. Maps to `--remove-chapters REGEX`. */
removeChapters?: string;
/** Don't remove chapters. Maps to `--no-remove-chapters`. */
noRemoveChapters?: boolean;
/** Force keyframes around chapters for accurate cuts. Maps to `--force-keyframes-at-cuts`. */
forceKeyframesAtCuts?: boolean;
/** Don't force keyframes. Maps to `--no-force-keyframes-at-cuts`. */
noForceKeyframesAtCuts?: boolean;
/** Enable a plugin-based postprocessor. Maps to `--use-postprocessor NAME`. */
usePostProcessor?: string[];
/**
* SponsorBlock categories to create chapters for.
* Available: sponsor, intro, outro, selfpromo, preview, filler, interaction, etc.
* Maps to `--sponsorblock-mark CATS`.
*/
sponsorblockMark?: string[];
/**
* SponsorBlock categories to remove from video.
* Available: sponsor, intro, outro, selfpromo, preview, filler, etc.
* Maps to `--sponsorblock-remove CATS`.
*/
sponsorblockRemove?: string[];
/** Template for SponsorBlock chapter titles. Maps to `--sponsorblock-chapter-title TEMPLATE`. */
sponsorblockChapterTitle?: string;
/** Disable all SponsorBlock options. Maps to `--no-sponsorblock`. */
noSponsorblock?: boolean;
/** SponsorBlock API URL. Maps to `--sponsorblock-api URL`. */
sponsorblockApi?: string;
/**
* Pass arguments to specific extractors.
* Maps to `--extractor-args IE_KEY:ARGS`.
* @example { youtube: ['player_skip=webpage', 'max_comments=100'] }
*/
extractorArgs?: {
[key: string]: string[];
};
/** Don't process dynamic DASH manifests. Maps to `--ignore-dynamic-mpd`. */
ignoreDynamicMpd?: boolean;
dumpPages?: boolean;
/** Don't split HLS at discontinuities. Maps to `--no-hls-split-discontinuity`. */
noHlsSplitDiscontinuity?: boolean;
/** HTTP Referer header. Maps to `--referer URL`. */
referer?: string;
/** Custom User-Agent header. Maps to `--user-agent UA`. */
userAgent?: string;
/** Additional HTTP headers. Maps to `--headers FIELD:VALUE`. */
headers?: {
[key: string]: string;
};
debugPrintCommandLine?: boolean;
writePages?: boolean;
/** List all available formats. Maps to `-F, --list-formats`. */
listFormats?: boolean;
/** List all available thumbnails. Maps to `--list-thumbnails`. */
listThumbnails?: boolean;
/**
* Additional yt-dlp options to append.
* @example ['--cookies', 'cookies.txt']
*/
additionalOptions?: string[];
/**
* Raw yt-dlp arguments (appended last).
* @example ['--match-filter', 'duration > 60']
*/
rawArgs?: string[];
}
interface YtDlpOptions {

@@ -436,15 +777,28 @@ binaryPath?: string;

interface VideoProgress {
/** Output filename (may be '-' when streaming to stdout) */
filename: string;
/** Current status: 'downloading' during download, 'finished' when complete */
status: 'downloading' | 'finished';
downloaded: number;
downloaded_str: string;
total: number;
total_str: string;
speed: number;
speed_str: string;
eta: number;
eta_str: string;
percentage: number;
percentage_str: string;
/** Downloaded bytes (may be undefined when streaming) */
downloaded?: number;
/** Formatted downloaded bytes string */
downloaded_str?: string;
/** Total bytes (may be undefined when file size is unknown) */
total?: number;
/** Formatted total bytes string */
total_str?: string;
/** Download speed in bytes/sec (may be undefined) */
speed?: number;
/** Formatted speed string */
speed_str?: string;
/** Estimated time remaining in seconds */
eta?: number;
/** Formatted ETA string */
eta_str?: string;
/** Download percentage (0-100, may be undefined when total is unknown) */
percentage?: number;
/** Formatted percentage string */
percentage_str?: string;
}
type VideoQuality = '2160p' | '1440p' | '1080p' | '720p' | '480p' | '360p' | '240p' | '144p' | 'highest' | 'lowest';
type VideoQuality = 'best' | '2160p' | '1440p' | '1080p' | '720p' | '480p' | '360p' | '240p' | '144p' | 'highest' | 'lowest';
type QualityOptions = {

@@ -456,2 +810,3 @@ videoonly: VideoQuality;

};
type AudioFormat = 'aac' | 'flac' | 'mp3' | 'm4a' | 'opus' | 'vorbis' | 'wav' | 'alac';
type TypeOptions = {

@@ -461,3 +816,3 @@ videoonly: 'mp4' | 'webm';

mergevideo: 'mkv' | 'mp4' | 'ogg' | 'webm' | 'flv';
audioonly: 'aac' | 'flac' | 'mp3' | 'm4a' | 'opus' | 'vorbis' | 'wav' | 'alac';
audioonly: AudioFormat;
};

@@ -472,2 +827,10 @@ type FormatKeyWord = keyof QualityOptions;

onProgress?: (p: VideoProgress) => void;
/**
* When true, adds `--print after_move:filepath` to capture final output paths.
*/
printPaths?: boolean;
/**
* Callback fired with final output paths when `printPaths` is enabled.
*/
onPaths?: (paths: string[]) => void;
}

@@ -516,3 +879,56 @@ type PipeResponse = {

}
type FormatTableRow = {
formatId: string;
extension: string;
resolution: string;
note: string;
raw: string;
};
type FormatTable = {
headers: string[];
rows: FormatTableRow[];
raw: string;
};
type FormatsResult = {
source: 'json';
info: VideoInfo | PlaylistInfo;
formats: VideoFormat[];
} | {
source: 'table';
table: FormatTable;
};
type UpdateResult = {
method: 'built-in' | 'download';
binaryPath: string;
version?: string;
verified?: boolean;
};
/**
* Result returned by downloadAsync.
*/
interface DownloadResult {
/** Raw command output */
output: string;
/** Downloaded video/audio file paths */
filePaths: string[];
/** Downloaded thumbnail paths (when writeThumbnail is true) */
thumbnailPaths: string[];
/** Downloaded subtitle paths (when writeSubs is true) */
subtitlePaths: string[];
}
/**
* Information about available subtitles.
*/
interface SubtitleInfo {
language: string;
languages: string[];
ext: string;
autoCaption: boolean;
}
/**
* Converts ArgsOptions into a string array of command-line arguments for yt-dlp.
* @param options - yt-dlp options
* @returns Array of command-line arguments
*/
declare function createArgs(options: ArgsOptions): string[];

@@ -526,2 +942,18 @@

/**
* Progress Utilities
* Provides functions for parsing and formatting yt-dlp progress output.
* @module utils/progress
*/
/**
* Parses a yt-dlp progress template string into a structured VideoProgress object.
* @param str - Raw progress output string from yt-dlp
* @returns Parsed VideoProgress object, or undefined if parsing fails
* @example
* const progress = stringToProgress('~ytdlp-progress-{"status":"downloading",...}');
* if (progress) {
* console.log(`${progress.percentage_str} complete`);
* }
*/
declare function stringToProgress(str: string): VideoProgress | undefined;

@@ -532,18 +964,73 @@

/**
* HTTP Request Utilities
* Provides functions for making HTTP/HTTPS requests and downloading files.
* @module utils/request
*/
/**
* Downloads a file from a URL to the local filesystem with progress reporting.
* @param url - URL of the file to download
* @param outputPath - Local path to save the file
* @throws Error if download fails or HTTP status is not 200
* @example
* await downloadFile('https://example.com/file.zip', '/tmp/file.zip');
*/
declare function downloadFile(url: string, outputPath: string): Promise<void>;
declare function downloadYtDlp(out?: string): Promise<string>;
declare function downloadYtDlpVerified(out?: string): Promise<{
path: string;
verified: boolean;
checksum?: string;
}>;
declare function findYtdlpBinary(): string | undefined;
declare const BIN_DIR: string;
/**
* Main YtDlp class - provides a high-level interface for yt-dlp operations.
*
* @example
* ```typescript
* const ytdlp = new YtDlp();
* const info = await ytdlp.getInfoAsync('https://youtube.com/watch?v=...');
* ```
*/
declare class YtDlp {
private readonly binaryPath;
private readonly ffmpegPath?;
/**
* Creates a new YtDlp instance.
* @param opt - Configuration options for binary paths
*/
constructor(opt?: YtDlpOptions);
/** Gets the context for download operations. */
private getDownloadContext;
/** Gets the context for stream operations. */
private getStreamContext;
/** Gets the context for info operations. */
private getInfoContext;
/**
* Asynchronously checks if yt-dlp and optionally FFmpeg are installed.
* @param options - Check options
* @returns Promise resolving to true if binaries are available
*/
checkInstallationAsync(options?: {
ffmpeg?: boolean;
}): Promise<boolean>;
/**
* Synchronously checks if yt-dlp and optionally FFmpeg are installed.
* @param options - Check options
* @returns true if binaries are available
*/
checkInstallation(options?: {
ffmpeg?: boolean;
}): boolean;
/**
* Executes yt-dlp asynchronously with the provided URL and options.
* @param url - Video URL
* @param options - Execution options with optional callbacks
* @returns Promise resolving to command output
*/
execAsync(url: string, options?: ArgsOptions & {

@@ -553,18 +1040,135 @@ onData?: (d: string) => void;

}): Promise<string>;
exec(url: string, options?: ArgsOptions): child_process.ChildProcessWithoutNullStreams;
/**
* Executes yt-dlp synchronously.
* @param url - Video URL
* @param options - Execution options
* @returns Spawned child process
*/
exec(url: string, options?: ArgsOptions): ChildProcess;
private _execute;
private _executeAsync;
private buildArgs;
download<F extends FormatKeyWord>(url: string, options?: Omit<FormatOptions<F>, 'onProgress'>): child_process.ChildProcessWithoutNullStreams;
downloadAsync<F extends FormatKeyWord>(url: string, options?: FormatOptions<F>): Promise<string>;
/**
* Downloads a video synchronously.
* @param url - Video URL
* @param options - Download options
* @returns Spawned child process with 'progress' event
*/
download<F extends FormatKeyWord>(url: string, options?: Omit<FormatOptions<F>, 'onProgress'>): ChildProcess;
/**
* Downloads a video asynchronously.
* @param url - Video URL
* @param options - Download options with progress callback
* @returns Promise resolving to DownloadResult with file paths
*/
downloadAsync<F extends FormatKeyWord>(url: string, options?: FormatOptions<F>): Promise<DownloadResult>;
/**
* Creates a stream for video download.
* @param url - Video URL
* @param options - Stream options
* @returns PipeResponse with pipe and pipeAsync methods
*/
stream<F extends FormatKeyWord>(url: string, options?: FormatOptions<F>): PipeResponse;
/**
* Fetches video or playlist info.
* @param url - Video or playlist URL
* @param options - Info options
* @returns Promise resolving to VideoInfo or PlaylistInfo
*/
getInfoAsync<T extends InfoType>(url: string, options?: InfoOptions): Promise<T extends 'video' ? VideoInfo : PlaylistInfo>;
/**
* Downloads audio only.
* @param url - Video URL
* @param format - Audio format (mp3, wav, flac, etc.)
* @param options - Additional options
*/
downloadAudio(url: string, format?: AudioFormat, options?: ArgsOptions): Promise<DownloadResult>;
/**
* Downloads video with specific quality.
* @param url - Video URL
* @param quality - Video quality (e.g., "1080p", "720p", "best")
* @param options - Additional options
*/
downloadVideo(url: string, quality?: VideoQuality, options?: ArgsOptions): Promise<DownloadResult>;
/**
* Gets available subtitles.
* @param url - Video URL
* @param options - Additional options
*/
getSubtitles(url: string, options?: ArgsOptions): Promise<SubtitleInfo[]>;
/**
* Fetches video comments.
* @param url - Video URL
* @param maxComments - Maximum comments to fetch
* @param options - Additional options
*/
getComments(url: string, maxComments?: number, options?: ArgsOptions): Promise<unknown[]>;
/**
* Gets direct media URLs.
* @param url - Video URL
* @param options - Args options
* @returns Promise resolving to array of URLs
*/
getDirectUrlsAsync(url: string, options?: ArgsOptions): Promise<string[]>;
/**
* Gets formats, preferring JSON with fallback to table parsing.
* @param url - Video URL
* @param options - Args options
* @returns Promise resolving to FormatsResult
*/
getFormatsAsync(url: string, options?: ArgsOptions): Promise<FormatsResult>;
/**
* Fetches video thumbnails.
* @param url - Video URL
* @returns Promise resolving to array of VideoThumbnail
*/
getThumbnailsAsync(url: string): Promise<VideoThumbnail[]>;
/**
* Fetches video title.
* @param url - Video URL
* @returns Promise resolving to title string
*/
getTitleAsync(url: string): Promise<string>;
/**
* Gets yt-dlp version.
* @returns Promise resolving to version string
*/
getVersionAsync(): Promise<string>;
/**
* Downloads FFmpeg binaries.
* @returns Promise resolving when download is complete
*/
downloadFFmpeg(): Promise<string | undefined>;
/**
* Gets video/audio content as a File object.
* Optimized: Uses --print before_dl:%(title)s.%(ext)s to capture
* filename during download - no separate info fetch required.
* @param url - Video URL
* @param options - File options with progress callback
* @returns Promise resolving to File object
*/
getFileAsync<F extends FormatKeyWord>(url: string, options?: GetFileOptions<F> & {
onProgress?: (p: VideoProgress) => void;
}): Promise<File>;
/**
* Gets media URLs using --print urls.
* @param url - Video URL
* @param options - Args options
* @returns Promise resolving to array of URLs
*/
getUrlsAsync(url: string, options?: ArgsOptions): Promise<string[]>;
/**
* Updates yt-dlp to the latest version.
* @param options - Update options
* @returns Promise resolving to UpdateResult
*/
updateYtDlpAsync(options?: {
preferBuiltIn?: boolean;
verifyChecksum?: boolean;
outDir?: string;
}): Promise<UpdateResult>;
}
/**
* Helper utilities exported for advanced usage.
*/
declare const helpers: {

@@ -583,5 +1187,6 @@ downloadFFmpeg: typeof downloadFFmpeg;

downloadYtDlp: typeof downloadYtDlp;
downloadYtDlpVerified: typeof downloadYtDlpVerified;
findYtdlpBinary: typeof findYtdlpBinary;
};
export { type ArgsOptions, BIN_DIR, type FormatOptions, type PlaylistInfo, type QualityOptions, type TypeOptions, type VideoFormat, type VideoInfo, type VideoProgress, type VideoThumbnail, YtDlp, type YtDlpOptions, helpers };
export { type ArgsOptions, BIN_DIR, type FormatOptions, type FormatTable, type FormatsResult, type PlaylistInfo, type QualityOptions, type TypeOptions, type UpdateResult, type VideoFormat, type VideoInfo, type VideoProgress, type VideoThumbnail, YtDlp, type YtDlpOptions, helpers };

@@ -1,293 +0,634 @@

import * as child_process from 'child_process';
import { ChildProcess } from 'child_process';
/**
* yt-dlp command-line options mapped to TypeScript.
* @see https://github.com/yt-dlp/yt-dlp#usage-and-options
*/
interface ArgsOptions {
/** Print help text and exit. Maps to `--help`. */
printHelp?: boolean;
/** Print program version and exit. Maps to `--version`. */
printVersion?: boolean;
/** Update yt-dlp to the latest version. Maps to `--update`. */
update?: boolean;
/** Do not check for updates. Maps to `--no-update`. */
noUpdate?: boolean;
/** Update to a specific version. Maps to `--update-to TAG`. */
updateTo?: string;
/** Continue on download errors. Maps to `--ignore-errors`. */
ignoreErrors?: boolean;
/** Continue with next video after error. Maps to `--no-abort-on-error`. */
noAbortOnError?: boolean;
/** Abort on download error. Maps to `--abort-on-error`. */
abortOnError?: boolean;
/** Display current browser user-agent. Maps to `--dump-user-agent`. */
dumpUserAgent?: boolean;
/** List all supported extractors. Maps to `--list-extractors`. */
listExtractors?: boolean;
/** Output descriptions of all extractors. Maps to `--extractor-descriptions`. */
extractorDescriptions?: boolean;
/** Use only specific extractors. Maps to `--use-extractors NAMES`. */
useExtractors?: string[];
/** Use this prefix for search queries. Maps to `--default-search PREFIX`. */
defaultSearch?: string;
/** Don't read configuration files. Maps to `--ignore-config`. */
ignoreConfig?: boolean;
/** Don't load config from default locations. Maps to `--no-config-location`. */
noConfigLocations?: boolean;
/** Location of the main config file. Maps to `--config-locations PATH`. */
configLocations?: string[];
/** Directories to load plugins from. Maps to `--plugin-dirs PATH`. */
pluginDirs?: string[];
/** Disable loading plugins. Maps to `--no-plugin-dirs`. */
noPluginDirs?: boolean;
/** Don't extract videos of a playlist. Maps to `--flat-playlist`. */
flatPlaylist?: boolean;
/** Extract videos of a playlist. Maps to `--no-flat-playlist`. */
noFlatPlaylist?: boolean;
/** Download livestreams from the start. Maps to `--live-from-start`. */
liveFromStart?: boolean;
/** Don't download from the start. Maps to `--no-live-from-start`. */
noLiveFromStart?: boolean;
/** Wait seconds for a video to become available. Maps to `--wait-for-video SEC`. */
waitForVideo?: number;
/** Don't wait for video. Maps to `--no-wait-for-video`. */
noWaitForVideo?: boolean;
/** Mark videos watched on YouTube. Maps to `--mark-watched`. */
markWatched?: boolean;
/** Don't mark videos watched. Maps to `--no-mark-watched`. */
noMarkWatched?: boolean;
/** Color output (always, never, auto, no_color). Maps to `--color WHEN`. */
color?: string;
/** Options to adjust behavior. Maps to `--compat-options OPTS`. */
compatOptions?: string[];
/** Command aliases. Maps to `--alias ALIAS CMD`. */
aliases?: string[];
/**
* JavaScript runtime for extractors requiring JS execution.
* Supported values: 'deno', 'node', 'phantomjs', etc.
* Maps to `--js-runtime RUNTIME`.
* @see https://github.com/yt-dlp/yt-dlp/wiki/EJS
*/
jsRuntime?: string;
/** Use the specified HTTP/HTTPS/SOCKS proxy. Maps to `--proxy URL`. */
proxy?: string;
/** Time to wait before giving up (seconds). Maps to `--socket-timeout SEC`. */
socketTimeout?: number;
/** Client-side IP address to bind to. Maps to `--source-address IP`. */
sourceAddress?: string;
/** Make all connections via IPv4. Maps to `--force-ipv4`. */
forceIpv4?: boolean;
/** Make all connections via IPv6. Maps to `--force-ipv6`. */
forceIpv6?: boolean;
/** Client to impersonate for requests. Maps to `--impersonate CLIENT`. */
impersonate?: string[];
/** List available clients to impersonate. Maps to `--list-impersonate-targets`. */
listImpersonateTargets?: boolean;
/** Enable file:// URLs. Maps to `--enable-file-urls`. */
enableFileUrls?: boolean;
/** Proxy for geo verification. Maps to `--geo-verification-proxy URL`. */
geoVerificationProxy?: string;
/** How to fake X-Forwarded-For header. Maps to `--xff VALUE`. */
xff?: string;
/** Bypass geographic restriction. Maps to `--geo-bypass`. */
geoBypass?: boolean;
/** Force bypass with a two-letter country code. Maps to `--geo-bypass-country CODE`. */
geoBypassCountry?: string;
/** Force bypass with an IP block. Maps to `--geo-bypass-ip-block IP_BLOCK`. */
geoBypassIpBlock?: string;
/** Playlist items to download (e.g., "1,3,5-7"). Maps to `--playlist-items ITEM_SPEC`. */
playlistItems?: string;
/** Don't download files smaller than SIZE. Maps to `--min-filesize SIZE`. */
minFilesize?: string;
/** Don't download files larger than SIZE. Maps to `--max-filesize SIZE`. */
maxFilesize?: string;
/** Download only videos uploaded on this date. Maps to `--date DATE`. */
date?: string;
/** Download only videos uploaded before this date. Maps to `--datebefore DATE`. */
dateBefore?: string;
/** Download only videos uploaded after this date. Maps to `--dateafter DATE`. */
dateAfter?: string;
/** Generic video filter. Maps to `--match-filter FILTER`. */
matchFilter?: string;
/** Do not use any --match-filter. Maps to `--no-match-filters`. */
noMatchFilters?: boolean;
/** Stop on filter match. Maps to `--break-match-filters FILTER`. */
breakMatchFilters?: string;
/** Do not --break-match-filters. Maps to `--no-break-match-filters`. */
noBreakMatchFilters?: boolean;
/** Download only the video for a single URL. Maps to `--no-playlist`. */
noPlaylist?: boolean;
/** Download the playlist if URL is a video and playlist. Maps to `--yes-playlist`. */
yesPlaylist?: boolean;
/** Download only videos suitable for the given age. Maps to `--age-limit YEARS`. */
ageLimit?: number;
/** Download only videos not in the archive. Maps to `--download-archive FILE`. */
downloadArchive?: string;
/** Do not use archive file. Maps to `--no-download-archive`. */
noDownloadArchive?: boolean;
/** Maximum number of files to download. Maps to `--max-downloads NUMBER`. */
maxDownloads?: number;
/** Stop if video is in archive. Maps to `--break-on-existing`. */
breakOnExisting?: boolean;
/** Do not stop on existing. Maps to `--no-break-on-existing`. */
noBreakOnExisting?: boolean;
/** Reset per input URL. Maps to `--break-per-input`. */
breakPerInput?: boolean;
/** Do not reset per input. Maps to `--no-break-per-input`. */
noBreakPerInput?: boolean;
/** Skip rest of playlist after N errors. Maps to `--skip-playlist-after-errors N`. */
skipPlaylistAfterErrors?: number;
/** Playlist video to start at (1-indexed). Maps to `--playlist-start NUMBER`. */
playlistStart?: number;
/** Playlist video to end at (1-indexed). Maps to `--playlist-end NUMBER`. */
playlistEnd?: number;
/** Download only videos whose title matches regex. Maps to `--match-title REGEX`. */
matchTitle?: string;
/** Skip videos whose title matches regex. Maps to `--reject-title REGEX`. */
rejectTitle?: string;
/** Download ads as well. Maps to `--include-ads`. */
includeAds?: boolean;
/** Stop on rejected title. Maps to `--break-on-reject`. */
breakOnReject?: boolean;
/**
* Number of fragments to download concurrently.
* Maps to `-N, --concurrent-fragments N`.
*/
concurrentFragments?: number;
/**
* Minimum download rate to avoid throttling (e.g., "100K").
* Re-extracts video data if download rate falls below this.
* Maps to `--throttled-rate RATE`.
*/
throttledRate?: string;
/** Number of retries for file access. Maps to `--file-access-retries RETRIES`. */
fileAccessRetries?: number;
retrySleep?: number;
/**
* Time to sleep between retries in seconds.
* Can be a number, "linear=START[:END[:STEP]]" or "exp=START[:END[:BASE]]".
* Use retrySleepType for type-specific sleep.
* Maps to `--retry-sleep [TYPE:]EXPR`.
*/
retrySleep?: number | string;
/**
* Type-specific retry sleep configuration.
* Keys: 'http', 'fragment', 'file_access', 'extractor'.
* Maps to `--retry-sleep TYPE:EXPR`.
*/
retrySleepByType?: {
[type: string]: string;
};
/** Delete fragments after download. Maps to `--no-keep-fragments`. */
noKeepFragments?: boolean;
/** Automatically resize the download buffer. Maps to `--resize-buffer`. */
resizeBuffer?: boolean;
/** Don't automatically resize buffer. Maps to `--no-resize-buffer`. */
noResizeBuffer?: boolean;
/** Process playlist entries as received. Maps to `--lazy-playlist`. */
lazyPlaylist?: boolean;
/** Parse entire playlist before downloading. Maps to `--no-lazy-playlist`. */
noLazyPlaylist?: boolean;
/** Don't use mpegts container for HLS. Maps to `--no-hls-use-mpegts`. */
noHlsUseMpegts?: boolean;
/**
* Download only matching sections (time range or chapters).
* Examples: "*10:15-inf", "intro", "*from-url".
* Maps to `--download-sections REGEX`.
*/
downloadSections?: string;
/**
* External downloader to use.
* Supports: native, aria2c, axel, curl, ffmpeg, httpie, wget.
* Maps to `--downloader [PROTO:]NAME`.
*/
downloader?: string;
/** Arguments to pass to external downloader. Maps to `--downloader-args NAME:ARGS`. */
downloaderArgs?: string;
playlistStart?: number;
playlistEnd?: number;
matchTitle?: string;
rejectTitle?: string;
includeAds?: boolean;
limitRate?: string;
breakOnReject?: boolean;
noDownload?: boolean;
playlistReverse?: boolean;
playlistRandom?: boolean;
xattrSetFilesize?: boolean;
hlsSplitDiscontinuity?: boolean;
geoBypass?: boolean;
geoBypassCountry?: string;
geoBypassIpBlock?: string;
batchFile?: string;
/** Number of retries (default 10). Maps to `-R, --retries RETRIES`. */
retries?: number;
/** Number of retries for a fragment. Maps to `--fragment-retries RETRIES`. */
fragmentRetries?: number;
/** Skip unavailable fragments. Maps to `--skip-unavailable-fragments`. */
skipUnavailableFragments?: boolean;
/** Abort download if a fragment is unavailable. Maps to `--abort-on-unavailable-fragments`. */
abortOnUnavailableFragment?: boolean;
/** Keep downloaded fragments on disk. Maps to `--keep-fragments`. */
keepFragments?: boolean;
/** Size of download buffer (e.g., "1024", "16K"). Maps to `--buffer-size SIZE`. */
bufferSize?: string;
/** Don't resume partial downloads. Maps to `--no-resume-dl`. */
noResumeDl?: boolean;
/** Force resume of partial downloads. Maps to `-c, --continue`. */
continueDownload?: boolean;
/** Do not resume partial downloads. Maps to `--no-continue`. */
noContinue?: boolean;
/** Maximum download rate (e.g., "50K", "4.2M"). Maps to `-r, --limit-rate RATE`. */
limitRate?: string;
/** Extract cookies from browser. Maps to `--cookies-from-browser BROWSER`. */
cookiesFromBrowser?: string;
/** Don't read cookies from files. Maps to `--no-cookies`. */
noCookies?: boolean;
/** Number of retries for known extractor errors. Maps to `--extractor-retries RETRIES`. */
extractorRetries?: number;
/** Process dynamic DASH manifests. Maps to `--allow-dynamic-mpd`. */
allowDynamicMpd?: boolean;
/** Use mpegts container for HLS. Maps to `--hls-use-mpegts`. */
hlsUseMpegts?: boolean;
/**
* Size of a chunk for chunk-based HTTP downloading.
* May help bypass throttling (experimental).
* Maps to `--http-chunk-size SIZE`.
*/
httpChunkSize?: string;
/** Skip download (useful with --print). Maps to `--no-download`. */
noDownload?: boolean;
/** Download playlist videos in reverse order. Maps to `--playlist-reverse`. */
playlistReverse?: boolean;
/** Download playlist videos in random order. Maps to `--playlist-random`. */
playlistRandom?: boolean;
/** Set xattr filesize. Maps to `--xattr-set-filesize`. */
xattrSetFilesize?: boolean;
/** Split HLS at discontinuities. Maps to `--hls-split-discontinuity`. */
hlsSplitDiscontinuity?: boolean;
/** File containing URLs to download. Maps to `-a, --batch-file FILE`. */
batchFile?: string;
/** Don't read batch file. Maps to `--no-batch-file`. */
noBatchFile?: boolean;
/** Limit filename length to N characters. Maps to `--trim-filenames LENGTH`. */
trimFileNames?: number;
/** Don't restrict characters in filenames. Maps to `--no-restrict-filenames`. */
noRestrictFilenames?: boolean;
/** Don't force Windows-safe filenames. Maps to `--no-windows-filenames`. */
noWindowsFilenames?: boolean;
/** Force resume of partially downloaded files (deprecated). */
continue?: boolean;
/** Write .part files. Maps to `--part`. */
part?: boolean;
/** Don't use .part files. Maps to `--no-part`. */
noPart?: boolean;
/** Use file modification time from server. Maps to `--mtime`. */
mtime?: boolean;
/** Don't use server mtime. Maps to `--no-mtime`. */
noMtime?: boolean;
/** Write video description to .description file. Maps to `--write-description`. */
writeDescription?: boolean;
/** Don't write description file. Maps to `--no-write-description`. */
noWriteDescription?: boolean;
/** Write video metadata to .info.json file. Maps to `--write-info-json`. */
writeInfoJson?: boolean;
/** Don't write info json. Maps to `--no-write-info-json`. */
noWriteInfoJson?: boolean;
/** Write playlist metadata files. Maps to `--write-playlist-metafiles`. */
writePlaylistMetafiles?: boolean;
/** Don't write playlist metadata. Maps to `--no-write-playlist-metafiles`. */
noWritePlaylistMetafiles?: boolean;
/** Remove some private fields from infojson. Maps to `--clean-info-json`. */
cleanInfoJson?: boolean;
/** Don't clean infojson. Maps to `--no-clean-info-json`. */
noCleanInfoJson?: boolean;
/** Write video comments to infojson. Maps to `--write-comments`. */
writeComments?: boolean;
/** Don't write comments. Maps to `--no-write-comments`. */
noWriteComments?: boolean;
/** JSON file with video metadata. Maps to `--load-info-json FILE`. */
loadInfoJson?: string;
/** File to read cookies from. Maps to `--cookies FILE`. */
cookies?: string;
/** Do not read cookies from browser. Maps to `--no-cookies-from-browser`. */
noCookiesFromBrowser?: boolean;
/** Location to store cached data. Maps to `--cache-dir DIR`. */
cacheDir?: string;
/** Disable caching. Maps to `--no-cache-dir`. */
noCacheDir?: boolean;
/** Delete all filesystem cache files. Maps to `--rm-cache-dir`. */
rmCacheDir?: boolean;
/**
* Paths for different file types.
* Maps to `-P, --paths [TYPES:]PATH`.
*/
paths?: {
[key: string]: string;
} | string;
/** Output filename template. Maps to `-o, --output TEMPLATE`. */
output?: string;
/** Placeholder for unavailable template. Maps to `--output-na-placeholder TEXT`. */
outputNaPlaceholder?: string;
/** Restrict filenames to ASCII. Maps to `--restrict-filenames`. */
restrictFilenames?: boolean;
/** Force filenames to be Windows-safe. Maps to `--windows-filenames`. */
windowsFilenames?: boolean;
/** Don't overwrite existing files. Maps to `--no-overwrites`. */
noOverwrites?: boolean;
/** Overwrite all video and metadata files. Maps to `--force-overwrites`. */
forceOverwrites?: boolean;
/** Don't overwrite the video. Maps to `--no-force-overwrites`. */
noForceOverwrites?: boolean;
/** Start autonumber from given value. Maps to `--autonumber-start NUMBER`. */
autonumberStart?: number;
/** Don't use .part files. Maps to `--no-part-files`. */
noPartFiles?: boolean;
noBatchFile?: boolean;
/** Write thumbnail image to disk. Maps to `--write-thumbnail`. */
writeThumbnail?: boolean;
/** Write all thumbnail formats to disk. Maps to `--write-all-thumbnails`. */
writeAllThumbnails?: boolean;
/** Don't write thumbnails. Maps to `--no-write-thumbnails`. */
noWriteThumbnails?: boolean;
/** Convert thumbnails to format. Maps to `--convert-thumbnails FORMAT`. */
convertThumbnails?: string;
/** Write internet shortcut file. Maps to `--write-link`. */
writeLink?: boolean;
/** Write .url Windows shortcut. Maps to `--write-url-link`. */
writeUrlLink?: boolean;
/** Write .webloc macOS shortcut. Maps to `--write-webloc-link`. */
writeWeblocLink?: boolean;
/** Write .lnk Windows shortcut. Maps to `--write-lnk-link`. */
writeLnkLink?: boolean;
/** Write .desktop Linux shortcut. Maps to `--write-desktop-link`. */
writeDesktopLink?: boolean;
/** Quiet mode, print only errors. Maps to `-q, --quiet`. */
quiet?: boolean;
/** Ignore warnings. Maps to `--no-warnings`. */
noWarnings?: boolean;
/** Simulate, don't download or write files. Maps to `-s, --simulate`. */
simulate?: boolean;
/** Don't simulate. Maps to `--no-simulate`. */
noSimulate?: boolean;
/** Ignore "no video formats" errors. Maps to `--ignore-no-formats-error`. */
ignoreNoFormatsError?: boolean;
/** Ignore EOF errors. Maps to `--ignore-eof-error`. */
ignoreEoFError?: boolean;
/** Don't ignore EOF errors. Maps to `--no-ignore-eof-error`. */
noIgnoreEoFError?: boolean;
/** Don't emit color codes. Maps to `--no-color`. */
noColor?: boolean;
/** Display HTTP traffic. Maps to `--print-traffic`. */
printTraffic?: boolean;
/** Display progress in console title. Maps to `--console-title`. */
consoleTitle?: boolean;
/** Print various debugging information. Maps to `-v, --verbose`. */
verbose?: boolean;
/** Activate quiet mode. Maps to `--no-quiet`. */
noQuiet?: boolean;
/** Don't ignore "no formats" errors. Maps to `--no-ignore-no-formats-error`. */
noIgnoreNoFormatsError?: boolean;
/** Don't display progress bar. Maps to `--no-progress`. */
noProgress?: boolean;
/** Display progress bar. Maps to `--progress`. */
progress?: boolean;
/** Simulate and print info as JSON (single video). Maps to `-J, --dump-single-json`. */
dumpSingleJson?: boolean;
/** Simulate and print info as JSON. Maps to `-j, --dump-json`. */
dumpJson?: boolean;
/** Print JSON (equivalent to -j). Maps to `--print-json`. */
printJson?: boolean;
/** Don't download video. Maps to `--skip-download`. */
skipDownload?: boolean;
/** Quiet mode, print given template. Maps to `-O, --print [WHEN:]TEMPLATE`. */
print?: string;
/** Print template to file. Maps to `--print-to-file [WHEN:]TEMPLATE FILE`. */
printToFile?: string;
/** Force write to archive. Maps to `--force-write-archive`. */
forceWriteArchive?: boolean;
/** Output progress on a new line. Maps to `--newline`. */
newline?: boolean;
/** Template for progress outputs. Maps to `--progress-template TEMPLATE`. */
progressTemplate?: string;
/** Time between progress updates in seconds. Maps to `--progress-delta SEC`. */
progressDelta?: number;
/** Print the yt-dlp command line. Maps to `--print-command-line`. */
debugPrintCommandLine?: boolean;
/** Write downloaded pages to files. Maps to `--write-pages`. */
writePages?: boolean;
/** Dump parsed web pages. Maps to `--dump-pages`. */
dumpPages?: boolean;
/** Force character encoding. Maps to `--encoding ENCODING`. */
encoding?: string;
/** Use an unencrypted connection. Maps to `--legacy-server-connect`. */
legacyServerConnect?: boolean;
/** Suppress HTTPS certificate validation. Maps to `--no-check-certificates`. */
noCheckCertificates?: boolean;
/** Use an unencrypted connection. Maps to `--prefer-insecure`. */
preferInsecure?: boolean;
/** Specify additional HTTP headers. Maps to `--add-header FIELD:VALUE`. */
addHeaders?: {
[key: string]: string;
};
/** Specify custom binary path. Maps to `--bin-path PATH`. */
binPath?: string;
/** Work around bidi issue. Maps to `--bidi-workaround`. */
bidiWorkaround?: boolean;
/** Seconds to sleep between requests. Maps to `--sleep-requests SEC`. */
sleepRequests?: number;
/** Seconds to sleep before each download. Maps to `--sleep-interval SEC`. */
sleepInterval?: number;
/** Max seconds to sleep. Maps to `--max-sleep-interval SEC`. */
maxSleepInterval?: number;
/** Seconds to sleep before subtitle download. Maps to `--sleep-subtitles SEC`. */
sleepSubtitles?: number;
/** Video format code. Maps to `-f, --format FORMAT`. */
format?: string;
/** Sort formats by given fields. Maps to `-S, --format-sort SORTORDER`. */
formatSort?: string[];
/** Force format sorting. Maps to `--format-sort-force`. */
formatSortForce?: boolean;
/** Don't force format sorting. Maps to `--no-format-sort-force`. */
noFormatSortForce?: boolean;
/** Preferred audio format (mp3, wav, etc.). Maps to `--audio-format FORMAT`. */
audioFormat?: string;
/** Preferred video format. Maps to `--video-format FORMAT`. */
videoFormat?: string;
/** Prefer free container formats. Maps to `--prefer-free-formats`. */
preferFreeFormats?: boolean;
/** Don't prefer free formats. Maps to `--no-prefer-free-formats`. */
noPreferFreeFormats?: boolean;
/** Force keyframes at cuts. Maps to `--yt-dlp-force-keyframes`. */
ytdlpForceKeyframes?: boolean;
/** Container for merging formats (mp4, mkv, etc.). Maps to `--merge-output-format FORMAT`. */
mergeOutputFormat?: string;
/** Merge multiple video streams. Maps to `--video-multistreams`. */
videoMultiStreams?: boolean;
/** Don't merge multiple video streams. Maps to `--no-video-multistreams`. */
noVideoMultiStreams?: boolean;
/** Merge multiple audio streams. Maps to `--audio-multistreams`. */
audioMultiStreams?: boolean;
/** Don't merge multiple audio streams. Maps to `--no-audio-multistreams`. */
noAudioMultiStreams?: boolean;
/** Check that formats are downloadable. Maps to `--check-formats`. */
checkFormats?: boolean;
/** Check all formats. Maps to `--check-all-formats`. */
checkAllFormats?: boolean;
/** Don't check formats. Maps to `--no-check-formats`. */
noCheckFormats?: boolean;
/** Write subtitle files. Maps to `--write-subs`. */
writeSubs?: boolean;
/** Write auto-generated subtitle files. Maps to `--write-auto-subs`. */
writeAutoSubs?: boolean;
/** Write all available subtitles. Maps to `--write-all-subs`. */
writeAllSubs?: boolean;
/** Don't write subtitle files. Maps to `--no-write-subs`. */
noWriteSubs?: boolean;
/** List available subtitles. Maps to `--list-subs`. */
listSubs?: boolean;
/** Subtitle format (srt, vtt, ass, etc.). Maps to `--sub-format FORMAT`. */
subFormat?: string;
/** Languages of subtitles to download. Maps to `--sub-langs LANGS`. */
subLangs?: string[];
/** Login username. Maps to `-u, --username USERNAME`. */
username?: string;
/** Login password. Maps to `-p, --password PASSWORD`. */
password?: string;
/** Two-factor auth code. Maps to `-2, --twofactor CODE`. */
twoFactor?: string;
/** Use .netrc authentication. Maps to `-n, --netrc`. */
netrc?: boolean;
/** Video password (vimeo, etc.). Maps to `--video-password PASSWORD`. */
videoPassword?: string;
/** Location of .netrc file. Maps to `--netrc-location PATH`. */
netrcLocation?: string;
/** Command to get netrc credentials. Maps to `--netrc-cmd COMMAND`. */
netrcCmd?: string;
apListMso?: boolean;
/** Client certificate file. Maps to `--client-certificate CERTFILE`. */
clientCertificate?: string;
/** Client certificate key file. Maps to `--client-certificate-key KEYFILE`. */
clientCertificateKey?: string;
/** Client certificate password. Maps to `--client-certificate-password PASSWORD`. */
clientCertificatePassword?: string;
/** List available MSOs. Maps to `--ap-list-mso`. */
apListMso?: boolean;
/** Adobe Pass MSO. Maps to `--ap-mso MSO`. */
apMso?: string;
/** Adobe Pass username. Maps to `--ap-username USERNAME`. */
apUsername?: string;
/** Adobe Pass password. Maps to `--ap-password PASSWORD`. */
apPassword?: string;
/** Extract and save audio. Maps to `-x, --extract-audio`. */
extractAudio?: boolean;
/** Audio quality (0-9 VBR or specific bitrate). Maps to `--audio-quality QUALITY`. */
audioQuality?: string;
/** Remux video to another container. Maps to `--remux-video FORMAT`. */
remuxVideo?: string;
/** Re-encode video to another format. Maps to `--recode-video FORMAT`. */
recodeVideo?: string;
/** Additional args for post processors. Maps to `--postprocessor-args NAME:ARGS`. */
postprocessorArgs?: {
[key: string]: string[];
};
/** Keep the original video. Maps to `-k, --keep-video`. */
keepVideo?: boolean;
/** Delete the original video. Maps to `--no-keep-video`. */
noKeepVideo?: boolean;
/** Overwrite post-processed files. Maps to `--post-overwrites`. */
postOverwrites?: boolean;
/** Don't overwrite post-processed files. Maps to `--no-post-overwrites`. */
noPostOverwrites?: boolean;
/** Embed subtitles in the video. Maps to `--embed-subs`. */
embedSubs?: boolean;
/** Don't embed subtitles. Maps to `--no-embed-subs`. */
noEmbedSubs?: boolean;
/** Embed thumbnail in the video. Maps to `--embed-thumbnail`. */
embedThumbnail?: boolean;
/** Don't embed thumbnail. Maps to `--no-embed-thumbnail`. */
noEmbedThumbnail?: boolean;
/** Embed metadata in the file. Maps to `--embed-metadata`. */
embedMetadata?: boolean;
/** Don't embed metadata. Maps to `--no-embed-metadata`. */
noEmbedMetadata?: boolean;
/** Embed chapters in the video. Maps to `--embed-chapters`. */
embedChapters?: boolean;
/** Don't embed chapters. Maps to `--no-embed-chapters`. */
noEmbedChapters?: boolean;
/** Embed info.json in video. Maps to `--embed-info-json`. */
embedInfoJson?: boolean;
/** Don't embed info.json. Maps to `--no-embed-info-json`. */
noEmbedInfoJson?: boolean;
/** Parse and modify metadata. Maps to `--parse-metadata FROM:TO`. */
parseMetadata?: {
[key: string]: string;
};
/** Replace text in a metadata field. Maps to `--replace-in-metadata FIELDS REGEX REPLACE`. */
replaceInMetadata?: {
[key: string]: [string, string];
};
/** Write extended attributes. Maps to `--xattrs`. */
xattrs?: boolean;
/** Concatenate playlist into a single file. Maps to `--concat-playlist POLICY`. */
concatPlaylist?: string;
/** Fix file problems (never, warn, detect_or_warn, force). Maps to `--fixup POLICY`. */
fixup?: string;
/** Location of FFmpeg binary. Maps to `--ffmpeg-location PATH`. */
ffmpegLocation?: string;
/** Execute command on file. Maps to `--exec CMD`. */
exec?: string;
/** Don't execute command. Maps to `--no-exec`. */
noExec?: boolean;
/** Convert subtitles to format. Maps to `--convert-subs FORMAT`. */
convertSubs?: string;
/** Split video by chapters. Maps to `--split-chapters`. */
splitChapters?: boolean;
/** Don't split by chapters. Maps to `--no-split-chapters`. */
noSplitChapters?: boolean;
/** Remove chapters matching regex. Maps to `--remove-chapters REGEX`. */
removeChapters?: string;
/** Don't remove chapters. Maps to `--no-remove-chapters`. */
noRemoveChapters?: boolean;
/** Force keyframes around chapters for accurate cuts. Maps to `--force-keyframes-at-cuts`. */
forceKeyframesAtCuts?: boolean;
/** Don't force keyframes. Maps to `--no-force-keyframes-at-cuts`. */
noForceKeyframesAtCuts?: boolean;
/** Enable a plugin-based postprocessor. Maps to `--use-postprocessor NAME`. */
usePostProcessor?: string[];
/**
* SponsorBlock categories to create chapters for.
* Available: sponsor, intro, outro, selfpromo, preview, filler, interaction, etc.
* Maps to `--sponsorblock-mark CATS`.
*/
sponsorblockMark?: string[];
/**
* SponsorBlock categories to remove from video.
* Available: sponsor, intro, outro, selfpromo, preview, filler, etc.
* Maps to `--sponsorblock-remove CATS`.
*/
sponsorblockRemove?: string[];
/** Template for SponsorBlock chapter titles. Maps to `--sponsorblock-chapter-title TEMPLATE`. */
sponsorblockChapterTitle?: string;
/** Disable all SponsorBlock options. Maps to `--no-sponsorblock`. */
noSponsorblock?: boolean;
/** SponsorBlock API URL. Maps to `--sponsorblock-api URL`. */
sponsorblockApi?: string;
/**
* Pass arguments to specific extractors.
* Maps to `--extractor-args IE_KEY:ARGS`.
* @example { youtube: ['player_skip=webpage', 'max_comments=100'] }
*/
extractorArgs?: {
[key: string]: string[];
};
/** Don't process dynamic DASH manifests. Maps to `--ignore-dynamic-mpd`. */
ignoreDynamicMpd?: boolean;
dumpPages?: boolean;
/** Don't split HLS at discontinuities. Maps to `--no-hls-split-discontinuity`. */
noHlsSplitDiscontinuity?: boolean;
/** HTTP Referer header. Maps to `--referer URL`. */
referer?: string;
/** Custom User-Agent header. Maps to `--user-agent UA`. */
userAgent?: string;
/** Additional HTTP headers. Maps to `--headers FIELD:VALUE`. */
headers?: {
[key: string]: string;
};
debugPrintCommandLine?: boolean;
writePages?: boolean;
/** List all available formats. Maps to `-F, --list-formats`. */
listFormats?: boolean;
/** List all available thumbnails. Maps to `--list-thumbnails`. */
listThumbnails?: boolean;
/**
* Additional yt-dlp options to append.
* @example ['--cookies', 'cookies.txt']
*/
additionalOptions?: string[];
/**
* Raw yt-dlp arguments (appended last).
* @example ['--match-filter', 'duration > 60']
*/
rawArgs?: string[];
}
interface YtDlpOptions {

@@ -436,15 +777,28 @@ binaryPath?: string;

interface VideoProgress {
/** Output filename (may be '-' when streaming to stdout) */
filename: string;
/** Current status: 'downloading' during download, 'finished' when complete */
status: 'downloading' | 'finished';
downloaded: number;
downloaded_str: string;
total: number;
total_str: string;
speed: number;
speed_str: string;
eta: number;
eta_str: string;
percentage: number;
percentage_str: string;
/** Downloaded bytes (may be undefined when streaming) */
downloaded?: number;
/** Formatted downloaded bytes string */
downloaded_str?: string;
/** Total bytes (may be undefined when file size is unknown) */
total?: number;
/** Formatted total bytes string */
total_str?: string;
/** Download speed in bytes/sec (may be undefined) */
speed?: number;
/** Formatted speed string */
speed_str?: string;
/** Estimated time remaining in seconds */
eta?: number;
/** Formatted ETA string */
eta_str?: string;
/** Download percentage (0-100, may be undefined when total is unknown) */
percentage?: number;
/** Formatted percentage string */
percentage_str?: string;
}
type VideoQuality = '2160p' | '1440p' | '1080p' | '720p' | '480p' | '360p' | '240p' | '144p' | 'highest' | 'lowest';
type VideoQuality = 'best' | '2160p' | '1440p' | '1080p' | '720p' | '480p' | '360p' | '240p' | '144p' | 'highest' | 'lowest';
type QualityOptions = {

@@ -456,2 +810,3 @@ videoonly: VideoQuality;

};
type AudioFormat = 'aac' | 'flac' | 'mp3' | 'm4a' | 'opus' | 'vorbis' | 'wav' | 'alac';
type TypeOptions = {

@@ -461,3 +816,3 @@ videoonly: 'mp4' | 'webm';

mergevideo: 'mkv' | 'mp4' | 'ogg' | 'webm' | 'flv';
audioonly: 'aac' | 'flac' | 'mp3' | 'm4a' | 'opus' | 'vorbis' | 'wav' | 'alac';
audioonly: AudioFormat;
};

@@ -472,2 +827,10 @@ type FormatKeyWord = keyof QualityOptions;

onProgress?: (p: VideoProgress) => void;
/**
* When true, adds `--print after_move:filepath` to capture final output paths.
*/
printPaths?: boolean;
/**
* Callback fired with final output paths when `printPaths` is enabled.
*/
onPaths?: (paths: string[]) => void;
}

@@ -516,3 +879,56 @@ type PipeResponse = {

}
type FormatTableRow = {
formatId: string;
extension: string;
resolution: string;
note: string;
raw: string;
};
type FormatTable = {
headers: string[];
rows: FormatTableRow[];
raw: string;
};
type FormatsResult = {
source: 'json';
info: VideoInfo | PlaylistInfo;
formats: VideoFormat[];
} | {
source: 'table';
table: FormatTable;
};
type UpdateResult = {
method: 'built-in' | 'download';
binaryPath: string;
version?: string;
verified?: boolean;
};
/**
* Result returned by downloadAsync.
*/
interface DownloadResult {
/** Raw command output */
output: string;
/** Downloaded video/audio file paths */
filePaths: string[];
/** Downloaded thumbnail paths (when writeThumbnail is true) */
thumbnailPaths: string[];
/** Downloaded subtitle paths (when writeSubs is true) */
subtitlePaths: string[];
}
/**
* Information about available subtitles.
*/
interface SubtitleInfo {
language: string;
languages: string[];
ext: string;
autoCaption: boolean;
}
/**
* Converts ArgsOptions into a string array of command-line arguments for yt-dlp.
* @param options - yt-dlp options
* @returns Array of command-line arguments
*/
declare function createArgs(options: ArgsOptions): string[];

@@ -526,2 +942,18 @@

/**
* Progress Utilities
* Provides functions for parsing and formatting yt-dlp progress output.
* @module utils/progress
*/
/**
* Parses a yt-dlp progress template string into a structured VideoProgress object.
* @param str - Raw progress output string from yt-dlp
* @returns Parsed VideoProgress object, or undefined if parsing fails
* @example
* const progress = stringToProgress('~ytdlp-progress-{"status":"downloading",...}');
* if (progress) {
* console.log(`${progress.percentage_str} complete`);
* }
*/
declare function stringToProgress(str: string): VideoProgress | undefined;

@@ -532,18 +964,73 @@

/**
* HTTP Request Utilities
* Provides functions for making HTTP/HTTPS requests and downloading files.
* @module utils/request
*/
/**
* Downloads a file from a URL to the local filesystem with progress reporting.
* @param url - URL of the file to download
* @param outputPath - Local path to save the file
* @throws Error if download fails or HTTP status is not 200
* @example
* await downloadFile('https://example.com/file.zip', '/tmp/file.zip');
*/
declare function downloadFile(url: string, outputPath: string): Promise<void>;
declare function downloadYtDlp(out?: string): Promise<string>;
declare function downloadYtDlpVerified(out?: string): Promise<{
path: string;
verified: boolean;
checksum?: string;
}>;
declare function findYtdlpBinary(): string | undefined;
declare const BIN_DIR: string;
/**
* Main YtDlp class - provides a high-level interface for yt-dlp operations.
*
* @example
* ```typescript
* const ytdlp = new YtDlp();
* const info = await ytdlp.getInfoAsync('https://youtube.com/watch?v=...');
* ```
*/
declare class YtDlp {
private readonly binaryPath;
private readonly ffmpegPath?;
/**
* Creates a new YtDlp instance.
* @param opt - Configuration options for binary paths
*/
constructor(opt?: YtDlpOptions);
/** Gets the context for download operations. */
private getDownloadContext;
/** Gets the context for stream operations. */
private getStreamContext;
/** Gets the context for info operations. */
private getInfoContext;
/**
* Asynchronously checks if yt-dlp and optionally FFmpeg are installed.
* @param options - Check options
* @returns Promise resolving to true if binaries are available
*/
checkInstallationAsync(options?: {
ffmpeg?: boolean;
}): Promise<boolean>;
/**
* Synchronously checks if yt-dlp and optionally FFmpeg are installed.
* @param options - Check options
* @returns true if binaries are available
*/
checkInstallation(options?: {
ffmpeg?: boolean;
}): boolean;
/**
* Executes yt-dlp asynchronously with the provided URL and options.
* @param url - Video URL
* @param options - Execution options with optional callbacks
* @returns Promise resolving to command output
*/
execAsync(url: string, options?: ArgsOptions & {

@@ -553,18 +1040,135 @@ onData?: (d: string) => void;

}): Promise<string>;
exec(url: string, options?: ArgsOptions): child_process.ChildProcessWithoutNullStreams;
/**
* Executes yt-dlp synchronously.
* @param url - Video URL
* @param options - Execution options
* @returns Spawned child process
*/
exec(url: string, options?: ArgsOptions): ChildProcess;
private _execute;
private _executeAsync;
private buildArgs;
download<F extends FormatKeyWord>(url: string, options?: Omit<FormatOptions<F>, 'onProgress'>): child_process.ChildProcessWithoutNullStreams;
downloadAsync<F extends FormatKeyWord>(url: string, options?: FormatOptions<F>): Promise<string>;
/**
* Downloads a video synchronously.
* @param url - Video URL
* @param options - Download options
* @returns Spawned child process with 'progress' event
*/
download<F extends FormatKeyWord>(url: string, options?: Omit<FormatOptions<F>, 'onProgress'>): ChildProcess;
/**
* Downloads a video asynchronously.
* @param url - Video URL
* @param options - Download options with progress callback
* @returns Promise resolving to DownloadResult with file paths
*/
downloadAsync<F extends FormatKeyWord>(url: string, options?: FormatOptions<F>): Promise<DownloadResult>;
/**
* Creates a stream for video download.
* @param url - Video URL
* @param options - Stream options
* @returns PipeResponse with pipe and pipeAsync methods
*/
stream<F extends FormatKeyWord>(url: string, options?: FormatOptions<F>): PipeResponse;
/**
* Fetches video or playlist info.
* @param url - Video or playlist URL
* @param options - Info options
* @returns Promise resolving to VideoInfo or PlaylistInfo
*/
getInfoAsync<T extends InfoType>(url: string, options?: InfoOptions): Promise<T extends 'video' ? VideoInfo : PlaylistInfo>;
/**
* Downloads audio only.
* @param url - Video URL
* @param format - Audio format (mp3, wav, flac, etc.)
* @param options - Additional options
*/
downloadAudio(url: string, format?: AudioFormat, options?: ArgsOptions): Promise<DownloadResult>;
/**
* Downloads video with specific quality.
* @param url - Video URL
* @param quality - Video quality (e.g., "1080p", "720p", "best")
* @param options - Additional options
*/
downloadVideo(url: string, quality?: VideoQuality, options?: ArgsOptions): Promise<DownloadResult>;
/**
* Gets available subtitles.
* @param url - Video URL
* @param options - Additional options
*/
getSubtitles(url: string, options?: ArgsOptions): Promise<SubtitleInfo[]>;
/**
* Fetches video comments.
* @param url - Video URL
* @param maxComments - Maximum comments to fetch
* @param options - Additional options
*/
getComments(url: string, maxComments?: number, options?: ArgsOptions): Promise<unknown[]>;
/**
* Gets direct media URLs.
* @param url - Video URL
* @param options - Args options
* @returns Promise resolving to array of URLs
*/
getDirectUrlsAsync(url: string, options?: ArgsOptions): Promise<string[]>;
/**
* Gets formats, preferring JSON with fallback to table parsing.
* @param url - Video URL
* @param options - Args options
* @returns Promise resolving to FormatsResult
*/
getFormatsAsync(url: string, options?: ArgsOptions): Promise<FormatsResult>;
/**
* Fetches video thumbnails.
* @param url - Video URL
* @returns Promise resolving to array of VideoThumbnail
*/
getThumbnailsAsync(url: string): Promise<VideoThumbnail[]>;
/**
* Fetches video title.
* @param url - Video URL
* @returns Promise resolving to title string
*/
getTitleAsync(url: string): Promise<string>;
/**
* Gets yt-dlp version.
* @returns Promise resolving to version string
*/
getVersionAsync(): Promise<string>;
/**
* Downloads FFmpeg binaries.
* @returns Promise resolving when download is complete
*/
downloadFFmpeg(): Promise<string | undefined>;
/**
* Gets video/audio content as a File object.
* Optimized: Uses --print before_dl:%(title)s.%(ext)s to capture
* filename during download - no separate info fetch required.
* @param url - Video URL
* @param options - File options with progress callback
* @returns Promise resolving to File object
*/
getFileAsync<F extends FormatKeyWord>(url: string, options?: GetFileOptions<F> & {
onProgress?: (p: VideoProgress) => void;
}): Promise<File>;
/**
* Gets media URLs using --print urls.
* @param url - Video URL
* @param options - Args options
* @returns Promise resolving to array of URLs
*/
getUrlsAsync(url: string, options?: ArgsOptions): Promise<string[]>;
/**
* Updates yt-dlp to the latest version.
* @param options - Update options
* @returns Promise resolving to UpdateResult
*/
updateYtDlpAsync(options?: {
preferBuiltIn?: boolean;
verifyChecksum?: boolean;
outDir?: string;
}): Promise<UpdateResult>;
}
/**
* Helper utilities exported for advanced usage.
*/
declare const helpers: {

@@ -583,5 +1187,6 @@ downloadFFmpeg: typeof downloadFFmpeg;

downloadYtDlp: typeof downloadYtDlp;
downloadYtDlpVerified: typeof downloadYtDlpVerified;
findYtdlpBinary: typeof findYtdlpBinary;
};
export { type ArgsOptions, BIN_DIR, type FormatOptions, type PlaylistInfo, type QualityOptions, type TypeOptions, type VideoFormat, type VideoInfo, type VideoProgress, type VideoThumbnail, YtDlp, type YtDlpOptions, helpers };
export { type ArgsOptions, BIN_DIR, type FormatOptions, type FormatTable, type FormatsResult, type PlaylistInfo, type QualityOptions, type TypeOptions, type UpdateResult, type VideoFormat, type VideoInfo, type VideoProgress, type VideoThumbnail, YtDlp, type YtDlpOptions, helpers };
+4
-4

@@ -1,4 +0,4 @@

"use strict";var Z=Object.create;var S=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var ee=Object.getOwnPropertyNames;var re=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty;var se=(e,r)=>{for(var t in r)S(e,t,{get:r[t],enumerable:!0})},U=(e,r,t,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of ee(r))!te.call(e,i)&&i!==t&&S(e,i,{get:()=>r[i],enumerable:!(s=X(r,i))||s.enumerable});return e};var c=(e,r,t)=>(t=e!=null?Z(re(e)):{},U(r||!e||!e.__esModule?S(t,"default",{value:e,enumerable:!0}):t,e)),ie=e=>U(S({},"__esModule",{value:!0}),e);var me={};se(me,{BIN_DIR:()=>d,YtDlp:()=>V,helpers:()=>he});module.exports=ie(me);var g=require("child_process"),k=c(require("fs")),G=c(require("path")),H=require("buffer");function x(e){let r=[];if(e.printHelp&&r.push("--help"),e.printVersion&&r.push("--version"),e.update&&r.push("--update"),e.noUpdate&&r.push("--no-update"),e.updateTo&&r.push("--update-to",e.updateTo),e.ignoreErrors&&r.push("--ignore-errors"),e.noAbortOnError&&r.push("--no-abort-on-error"),e.abortOnError&&r.push("--abort-on-error"),e.dumpUserAgent&&r.push("--dump-user-agent"),e.listExtractors&&r.push("--list-extractors"),e.extractorDescriptions&&r.push("--extractor-descriptions"),e.useExtractors&&e.useExtractors.length>0&&r.push("--use-extractors",e.useExtractors.join(",")),e.defaultSearch&&r.push("--default-search",e.defaultSearch),e.ignoreConfig&&r.push("--ignore-config"),e.noConfigLocations&&r.push("--no-config-location"),e.configLocations&&e.configLocations.length>0&&r.push("--config-locations",...e.configLocations),e.pluginDirs&&e.pluginDirs.length>0)for(let t of e.pluginDirs)r.push("--plugin-dirs",t);if(e.noPluginDirs&&r.push("--no-plugin-dirs"),e.flatPlaylist&&r.push("--flat-playlist"),e.noFlatPlaylist&&r.push("--no-flat-playlist"),e.liveFromStart&&r.push("--live-from-start"),e.noLiveFromStart&&r.push("--no-live-from-start"),e.waitForVideo&&r.push("--wait-for-video",e.waitForVideo.toString()),e.noWaitForVideo&&r.push("--no-wait-for-video"),e.markWatched&&r.push("--mark-watched"),e.noMarkWatched&&r.push("--no-mark-watched"),e.color&&r.push("--color",e.color),e.compatOptions&&e.compatOptions.length>0&&r.push("--compat-options",e.compatOptions.join(",")),e.aliases&&e.aliases.length>0&&r.push("--alias",...e.aliases),e.proxy&&r.push("--proxy",e.proxy),e.socketTimeout&&r.push("--socket-timeout",e.socketTimeout.toString()),e.sourceAddress&&r.push("--source-address",e.sourceAddress),e.impersonate&&e.impersonate.length>0&&r.push("--impersonate",e.impersonate.join(",")),e.listImpersonateTargets&&r.push("--list-impersonate-targets"),e.forceIpv4&&r.push("--force-ipv4"),e.forceIpv6&&r.push("--force-ipv6"),e.enableFileUrls&&r.push("--enable-file-urls"),e.geoVerificationProxy&&r.push("--geo-verification-proxy",e.geoVerificationProxy),e.xff&&r.push("--xff",e.xff),e.playlistItems&&r.push("--playlist-items",e.playlistItems),e.minFilesize&&r.push("--min-filesize",e.minFilesize),e.maxFilesize&&r.push("--max-filesize",e.maxFilesize),e.date&&r.push("--date",e.date),e.dateBefore&&r.push("--datebefore",e.dateBefore),e.dateAfter&&r.push("--dateafter",e.dateAfter),e.matchFilter&&r.push("--match-filter",e.matchFilter),e.noMatchFilters&&r.push("--no-match-filters"),e.breakMatchFilters&&r.push("--break-match-filters",e.breakMatchFilters),e.noBreakMatchFilters&&r.push("--no-break-match-filters"),e.noPlaylist&&r.push("--no-playlist"),e.yesPlaylist&&r.push("--yes-playlist"),e.ageLimit&&r.push("--age-limit",e.ageLimit.toString()),e.downloadArchive&&r.push("--download-archive",e.downloadArchive),e.noDownloadArchive&&r.push("--no-download-archive"),e.maxDownloads&&r.push("--max-downloads",e.maxDownloads.toString()),e.breakOnExisting&&r.push("--break-on-existing"),e.noBreakOnExisting&&r.push("--no-break-on-existing"),e.breakPerInput&&r.push("--break-per-input"),e.noBreakPerInput&&r.push("--break-per-input"),e.skipPlaylistAfterErrors&&r.push("--skip-playlist-after-errors",e.skipPlaylistAfterErrors.toString()),e.concurrentFragments&&r.push("--concurrent-fragments",e.concurrentFragments.toString()),e.limitRate&&r.push("--limit-rate",e.limitRate),e.throttledRate&&r.push("--throttled-rate",e.throttledRate),e.retries&&r.push("--retries",e.retries.toString()),e.fileAccessRetries&&r.push("--file-access-retries",e.fileAccessRetries.toString()),e.fragmentRetries&&r.push("--fragment-retries",e.fragmentRetries.toString()),e.retrySleep&&r.push("--retry-sleep",e.retrySleep.toString()),e.skipUnavailableFragments&&r.push("--skip-unavailable-fragments"),e.abortOnUnavailableFragment&&r.push("--abort-on-unavailable-fragment"),e.keepFragments&&r.push("--keep-fragments"),e.noKeepFragments&&r.push("--no-keep-fragments"),e.bufferSize&&r.push("--buffer-size",e.bufferSize),e.resizeBuffer&&r.push("--resize-buffer"),e.noResizeBuffer&&r.push("--no-resize-buffer"),e.httpChunkSize&&r.push("--http-chunk-size",e.httpChunkSize),e.playlistRandom&&r.push("--playlist-random"),e.lazyPlaylist&&r.push("--lazy-playlist"),e.noLazyPlaylist&&r.push("--no-lazy-playlist"),e.xattrSetFilesize&&r.push("--xattr-set-filesize"),e.hlsUseMpegts&&r.push("--hls-use-mpegts"),e.noHlsUseMpegts&&r.push("--no-hls-use-mpegts"),e.downloadSections&&r.push("--download-sections",e.downloadSections.toString()),e.downloader&&r.push("--downloader",e.downloader),e.downloaderArgs&&r.push("--downloader-args",e.downloaderArgs),e.batchFile&&r.push("--batch-file",e.batchFile),e.noBatchFile&&r.push("--no-batch-file"),e.paths)if(typeof e.paths=="string")r.push("--paths",e.paths);else for(let[t,s]of Object.entries(e.paths))r.push("--paths",`${t}:${s}`);if(e.output&&r.push("-o",e.output),e.outputNaPlaceholder&&r.push("--output-na-placeholder",e.outputNaPlaceholder),e.restrictFilenames&&r.push("--restrict-filenames"),e.noRestrictFilenames&&r.push("--no-restrict-filenames"),e.windowsFilenames&&r.push("--windows-filenames"),e.noWindowsFilenames&&r.push("--no-windows-filenames"),e.trimFileNames&&r.push("--trim-file-names",e.trimFileNames.toString()),e.noOverwrites&&r.push("--no-overwrites"),e.forceOverwrites&&r.push("--force-overwrites"),e.noForceOverwrites&&r.push("--no-force-overwrites"),e.continue&&r.push("--continue"),e.noContinue&&r.push("--no-continue"),e.part&&r.push("--part"),e.noPart&&r.push("--no-part"),e.mtime&&r.push("--mtime"),e.noMtime&&r.push("--no-mtime"),e.writeDescription&&r.push("--write-description"),e.noWriteDescription&&r.push("--no-write-description"),e.writeInfoJson&&r.push("--write-info-json"),e.noWriteInfoJson&&r.push("--no-write-info-json"),e.writePlaylistMetafiles&&r.push("--write-playlist-metafiles"),e.noWritePlaylistMetafiles&&r.push("--no-write-playlist-metafiles"),e.cleanInfoJson&&r.push("--clean-info-json"),e.noCleanInfoJson&&r.push("--no-clean-info-json"),e.writeComments&&r.push("--write-comments"),e.noWriteComments&&r.push("--no-write-comments"),e.loadInfoJson&&r.push("--load-info-json",e.loadInfoJson.toString()),e.cookies&&r.push("--cookies",e.cookies),e.noCookies&&r.push("--no-cookies"),e.cookiesFromBrowser&&r.push("--cookies-from-browser",e.cookiesFromBrowser),e.noCookiesFromBrowser&&r.push("--no-cookies-from-browser"),e.cacheDir&&r.push("--cache-dir",e.cacheDir),e.noCacheDir&&r.push("--no-cache-dir"),e.rmCacheDir&&r.push("--rm-cache-dir"),e.writeThumbnail&&r.push("--write-thumbnail"),e.noWriteThumbnails&&r.push("--no-write-thumbnails"),e.writeAllThumbnails&&r.push("--write-all-thumbnails"),e.listThumbnails&&r.push("--list-thumbnails"),e.writeLink&&r.push("--write-link"),e.writeUrlLink&&r.push("--write-url-link"),e.writeWeblocLink&&r.push("--write-webloc-link"),e.writeDesktopLink&&r.push("--write-desktop-link"),e.quiet&&r.push("--quiet"),e.noQuiet&&r.push("--no-quiet"),e.noWarnings&&r.push("--no-warnings"),e.simulate&&r.push("--simulate"),e.noSimulate&&r.push("--no-simulate"),e.ignoreNoFormatsError&&r.push("--ignore-no-formats-error"),e.noIgnoreNoFormatsError&&r.push("--no-ignore-no-formats-error"),e.skipDownload&&r.push("--skip-download"),e.print&&r.push("--print",e.print),e.printToFile&&r.push("--print-to-file",e.printToFile),e.dumpJson&&r.push("--dump-json"),e.dumpSingleJson&&r.push("--dump-single-json"),e.forceWriteArchive&&r.push("--force-write-archive"),e.newline&&r.push("--newline"),e.noProgress&&r.push("--no-progress"),e.progress&&r.push("--progress"),e.consoleTitle&&r.push("--console-title"),e.progressTemplate&&r.push("--progress-template",e.progressTemplate),e.progressDelta&&r.push("--progress-delta",e.progressDelta.toString()),e.verbose&&r.push("--verbose"),e.dumpPages&&r.push("--dump-pages"),e.writePages&&r.push("--write-pages"),e.printTraffic&&r.push("--print-traffic"),e.encoding&&r.push("--encoding",e.encoding),e.legacyServerConnect&&r.push("--legacy-server-connect"),e.noCheckCertificates&&r.push("--no-check-certificates"),e.preferInsecure&&r.push("--prefer-insecure"),e.addHeaders)for(let[t,s]of Object.entries(e.addHeaders))r.push("--add-headers",`${t}:${s}`);if(e.bidiWorkaround&&r.push("--bidi-workaround"),e.sleepRequests&&r.push("--sleep-requests",e.sleepRequests.toString()),e.sleepInterval&&r.push("--sleep-interval",e.sleepInterval.toString()),e.maxSleepInterval&&r.push("--max-sleep-interval",e.maxSleepInterval.toString()),e.sleepSubtitles&&r.push("--sleep-subtitles",e.sleepSubtitles.toString()),e.format&&r.push("-f",e.format),e.formatSort&&e.formatSort.length>0&&r.push("--format-sort",e.formatSort.join(",")),e.formatSortForce&&r.push("--format-sort-force"),e.noFormatSortForce&&r.push("--no-format-sort-force"),e.videoMultiStreams&&r.push("--video-multistreams"),e.noVideoMultiStreams&&r.push("--no-video-multistreams"),e.audioMultiStreams&&r.push("--audio-multistreams"),e.noAudioMultiStreams&&r.push("--no-audio-multistreams"),e.preferFreeFormats&&r.push("--prefer-free-formats"),e.noPreferFreeFormats&&r.push("--no-prefer-free-formats"),e.checkFormats&&r.push("--check-formats"),e.checkAllFormats&&r.push("--check-all-formats"),e.noCheckFormats&&r.push("--no-check-formats"),e.listFormats&&r.push("--list-formats"),e.mergeOutputFormat&&r.push("--merge-output-format",e.mergeOutputFormat),e.writeSubs&&r.push("--write-subs"),e.noWriteSubs&&r.push("--no-write-subs"),e.writeAutoSubs&&r.push("--write-auto-subs"),e.writeAllSubs&&r.push("--all-subs"),e.listSubs&&r.push("--list-subs"),e.subFormat&&r.push("--sub-format",e.subFormat),e.subLangs&&e.subLangs.length>0&&r.push("--sub-langs",e.subLangs.join(",")),e.username&&r.push("--username",e.username),e.password&&r.push("--password",e.password),e.twoFactor&&r.push("--twofactor",e.twoFactor),e.netrc&&r.push("--netrc"),e.videoPassword&&r.push("--video-password",e.videoPassword),e.apMso&&r.push("--ap-mso",e.apMso),e.apUsername&&r.push("--ap-username",e.apUsername),e.apPassword&&r.push("--ap-password",e.apPassword),e.netrcLocation&&r.push("--netrc-location",e.netrcLocation),e.netrcCmd&&r.push("--netrc-cmd",e.netrcCmd),e.apListMso&&r.push("--ap-list-mso"),e.clientCertificate&&r.push("--client-certificate",e.clientCertificate),e.clientCertificateKey&&r.push("--client-certificate-key",e.clientCertificateKey),e.clientCertificatePassword&&r.push("--client-certificate-password",e.clientCertificatePassword),e.extractorRetries!==void 0&&r.push("--extractor-retries",e.extractorRetries.toString()),e.allowDynamicMpd&&r.push("--allow-dynamic-mpd"),e.ignoreDynamicMpd&&r.push("--ignore-dynamic-mpd"),e.hlsSplitDiscontinuity&&r.push("--hls-split-discontinuity"),e.noHlsSplitDiscontinuity&&r.push("--no-hls-split-discontinuity"),e.extractorArgs)for(let[t,s]of Object.entries(e.extractorArgs))r.push("--extractor-args",`${t}:${s.join(" ")}`);if(e.playlistStart!==void 0&&r.push("--playlist-start",e.playlistStart.toString()),e.playlistEnd!==void 0&&r.push("--playlist-end",e.playlistEnd.toString()),e.matchTitle&&r.push("--match-title",e.matchTitle),e.rejectTitle&&r.push("--reject-title",e.rejectTitle),e.includeAds&&r.push("--include-ads"),e.breakOnReject&&r.push("--break-on-reject"),e.noDownload&&r.push("--no-download"),e.playlistReverse&&r.push("--playlist-reverse"),e.geoBypass&&r.push("--geo-bypass"),e.geoBypassCountry&&r.push("--geo-bypass-country",e.geoBypassCountry),e.geoBypassIpBlock&&r.push("--geo-bypass-ip-block",e.geoBypassIpBlock),e.convertThumbnails&&r.push("--convert-thumbnails",e.convertThumbnails),e.writeLink&&r.push("--write-link"),e.writeUrlLink&&r.push("--write-url-link"),e.writeWeblocLink&&r.push("--write-webloc-link"),e.writeLnkLink&&r.push("--write-lnk-link"),e.userAgent&&r.push("--user-agent",e.userAgent),e.extractAudio&&r.push("--extract-audio"),e.audioFormat&&r.push("--audio-format",e.audioFormat),e.audioQuality&&r.push("--audio-quality",e.audioQuality),e.remuxVideo&&r.push("--remux-video",e.remuxVideo),e.recodeVideo&&r.push("--recode-video",e.recodeVideo),e.postprocessorArgs)for(let[t,s]of Object.entries(e.postprocessorArgs))r.push("--postprocessor-args",`${t}:${s.join(" ")}`);if(e.keepVideo&&r.push("--keep-video"),e.noKeepVideo&&r.push("--no-keep-video"),e.postOverwrites&&r.push("--post-overwrites"),e.noPostOverwrites&&r.push("--no-post-overwrites"),e.embedSubs&&r.push("--embed-subs"),e.noEmbedSubs&&r.push("--no-embed-subs"),e.embedThumbnail&&r.push("--embed-thumbnail"),e.noEmbedThumbnail&&r.push("--no-embed-thumbnail"),e.embedMetadata&&r.push("--embed-metadata"),e.noEmbedMetadata&&r.push("--no-embed-metadata"),e.embedChapters&&r.push("--embed-chapters"),e.noEmbedChapters&&r.push("--no-embed-chapters"),e.embedInfoJson&&r.push("--embed-info-json"),e.noEmbedInfoJson&&r.push("--no-embed-info-json"),e.parseMetadata)for(let[t,s]of Object.entries(e.parseMetadata))r.push("--parse-metadata",`${t}:${s}`);if(e.replaceInMetadata)for(let[t,[s,i]]of Object.entries(e.replaceInMetadata))r.push("--replace-in-metadata",`${t} ${s} ${i}`);if(e.xattrs&&r.push("--xattrs"),e.concatPlaylist&&r.push("--concat-playlist",e.concatPlaylist),e.fixup&&r.push("--fixup",e.fixup),e.ffmpegLocation&&r.push("--ffmpeg-location",e.ffmpegLocation),e.exec&&r.push("--exec",e.exec),e.noExec&&r.push("--no-exec"),e.convertSubs&&r.push("--convert-subs",e.convertSubs),e.convertThumbnails&&r.push("--convert-thumbnails",e.convertThumbnails),e.splitChapters&&r.push("--split-chapters"),e.noSplitChapters&&r.push("--no-split-chapters"),e.removeChapters&&r.push("--remove-chapters",e.removeChapters),e.noRemoveChapters&&r.push("--no-remove-chapters"),e.forceKeyframesAtCuts&&r.push("--force-keyframes-at-cuts"),e.noForceKeyframesAtCuts&&r.push("--no-force-keyframes-at-cuts"),e.usePostProcessor&&e.usePostProcessor.length>0)for(let t of e.usePostProcessor)r.push("--use-postprocessor",t);return e.sponsorblockMark&&e.sponsorblockMark.length>0&&r.push("--sponsorblock-mark",e.sponsorblockMark.join(",")),e.sponsorblockRemove&&e.sponsorblockRemove.length>0&&r.push("--sponsorblock-remove",e.sponsorblockRemove.join(",")),e.sponsorblockChapterTitle&&r.push("--sponsorblock-chapter-title",e.sponsorblockChapterTitle),e.noSponsorblock&&r.push("--no-sponsorblock"),e.sponsorblockApi&&r.push("--sponsorblock-api",e.sponsorblockApi),e.additionalOptions&&e.additionalOptions.length>0&&r.push(...e.additionalOptions),r}function R(e){let r=[],t=e.split(`
`).slice(1);for(let s of t){let i=s.match(/(\d+)\s+(\S+)\s+(\S+)\s+(https:\/\/[\S]+)/);i&&r.push({id:parseInt(i[1],10),width:i[2]==="unknown"?"unknown":parseInt(i[2],10),height:i[3]==="unknown"?"unknown":parseInt(i[3],10),url:i[4]})}return r}var K={"2160p":"bv*[height<=2160]","1440p":"bv*[height<=1440]","1080p":"bv*[height<=1080]","720p":"bv*[height<=720]","480p":"bv*[height<=480]","360p":"bv*[height<=360]","240p":"bv*[height<=240]","144p":"bv*[height<=133]",highest:"bv*",lowest:"wv*"};function y(e){if(!e)return[];if(typeof e=="string")return["-f",e];if(Object.keys(e).length===0)return["-f","bv*+ba"];let r=[],{filter:t,quality:s,type:i}=e;return t==="audioonly"&&(r=["-x","--audio-format",i||"mp3","--audio-quality",s?s.toString():"5"]),t==="videoonly"&&(r=["-f",(s?K[s]:"bv*")+"[acodec=none]"]),t==="audioandvideo"&&(r=["-f",(s=="lowest"?"w*":"b*")+"[vcodec!=none][acodec!=none][ext="+(i||"mp4")+"]"]),t==="mergevideo"&&(r=["-f",`${s?K[s]:"bv*"}+ba`],i&&r.push("--merge-output-format",i)),r}function A(e){if(!e||typeof e=="string")return"video/mp4";let{filter:r,type:t}=e;switch(r){case"videoonly":case"audioandvideo":switch(t){case"mp4":return"video/mp4";case"webm":return"video/webm";default:return"video/mp4"}case"audioonly":switch(t){case"aac":return"audio/aac";case"flac":return"audio/flac";case"mp3":return"audio/mp3";case"m4a":return"audio/mp4";case"opus":return"audio/opus";case"vorbis":return"audio/vorbis";case"wav":return"audio/wav";case"alac":return"audio/mp4";default:return"audio/mpeg"}case"mergevideo":switch(t){case"webm":return"video/webm";case"mkv":return"video/x-matroska";case"ogg":return"video/ogg";case"flv":return"video/x-flv";default:return"video/mp4"}}}function D(e){if(!e||typeof e=="string")return"mp4";let{filter:r,type:t}=e;return t||(r==="audioonly"?"mp3":"mp4")}var _='bright-{"status":"%(progress.status)s","downloaded":"%(progress.downloaded_bytes)s","total":"%(progress.total_bytes)s","total_estimate":"%(progress.total_bytes_estimate)s","speed":"%(progress.speed)s","eta":"%(progress.eta)s"}';function M(e,r=2){let t=Number(e);if(t===0||isNaN(t))return t+" Bytes";let s=1024,i=r<0?0:r,n=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],a=Math.floor(Math.log(t)/Math.log(s));return parseFloat((t/Math.pow(s,a)).toFixed(i))+" "+n[a]}function ae(e,r,t){let s=Math.pow(t||10,r);return Math.round(e*s)/s}function q(e,r){return ae(100*Number(e)/Number(r),2)}function ne(e){e=Number(e);let r=Math.floor(e/3600),t=Math.floor(e%3600/60),s=Math.floor(e%3600%60),i=r>0?r+(r==1?" hour, ":" hours, "):"",n=t>0?t+(t==1?" minute, ":" minutes, "):"",a=s>=0?s+(s==1?" second":" seconds"):"";return i+n+a}function m(e){try{if(!e.includes("bright"))throw new Error;let r=e.split("\r")?.[1]?.trim()?.split("-")?.[1];if(!r)throw new Error;let t=JSON.parse(r),s=isNaN(Number(t.total))?Number(t.total_estimate):Number(t.total);return{status:t.status,downloaded:Number(t.downloaded),downloaded_str:M(t.downloaded),total:s,total_str:M(s),speed:Number(t.speed),speed_str:M(t.speed)+"/s",eta:Number(t.eta),eta_str:ne(t.eta),percentage:q(t.downloaded,s),percentage_str:q(t.downloaded,s)+"%"}}catch{return}}var W=require("stream");var O=c(require("path")),F=c(require("fs"));var oe=c(require("https")),fe=c(require("http")),C=require("url"),h=c(require("fs"));function J(e,r={}){return new Promise((t,s)=>{let a=(new C.URL(e).protocol==="https:"?oe:fe).get(e,r,o=>{if(o.statusCode>=300&&o.statusCode<400&&o.headers.location){let u=new C.URL(o.headers.location,e).toString();J(u,r).then(t).catch(s);return}t(o)});a.on("error",s),a.setTimeout(3e4,()=>{a.destroy(),s(new Error("Request timed out"))})})}async function w(e,r){try{let t=h.createWriteStream(r),s=await J(e);if(s.statusCode!==200)throw t.close(),h.unlinkSync(r),new Error(`Failed to download file: ${s.statusCode} ${s.statusMessage}`);let i=parseInt(s.headers["content-length"]||"0",10),n=0;return s.on("data",a=>{n+=a.length;let o=n/i*100;process.stdout.write(`Progress: ${Math.round(o)}%\r`)}),s.pipe(t),new Promise((a,o)=>{t.on("finish",()=>{t.close(),console.log(`
Download complete!`),a()}),t.on("error",u=>{t.close(),h.unlinkSync(r),o(u)}),s.on("error",u=>{t.close(),h.unlinkSync(r),o(u)})})}catch(t){throw h.existsSync(r)&&h.unlinkSync(r),t}}var ue="https://github.com/iqbal-rashed/ytdlp-nodejs/releases/download/ffmpeg-latest",N={win32:{x64:["win-x64-ffmpeg.exe","win-x64-ffprobe.exe"],ia32:["win-ia32-ffmpeg.exe","win-ia32-ffprobe.exe"],arm64:["win-arm64-ffmpeg.exe","win-arm64-ffprobe.exe"]},linux:{x64:["linux-x64-ffmpeg","linux-x64-ffprobe"],arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]},darwin:{x64:["macos-x64-ffmpeg","macos-x64-ffprobe"],arm64:["macos-arm64-ffmpeg","macos-arm64-ffprobe"]},android:{arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]}};function Q(){let e=process.platform,r=process.arch;if(!N[e]||!N[e][r])throw new Error(`No FFmpeg build available for platform: ${e}, architecture: ${r}`);return N[e][r]}async function $(e){let r=e||d,t=v();if(t)return t;try{let s=Q();if(!s.length)throw new Error;let i=s.map(a=>`${ue}/${a}`),n=s.map(a=>O.default.join(r,String(a.split("-").pop())));F.default.existsSync(r)||F.default.mkdirSync(r,{recursive:!0}),console.log("Downloading FFmpeg and FFprobe...");for(let a=0;a<s.length;a++){let o=i[a],u=n[a];console.log("Downloading...",O.default.basename(o)),await w(o,u)}try{for(let a of n)F.default.chmodSync(a,493)}catch{console.log("Note: Could not set executable permissions (likely Windows)")}return v()}catch(s){throw console.error(`Download failed: ${s}`),s}}function v(){try{let e=Q();if(!e.length)throw new Error;let r=O.default.join(d,String(e[0].split("-").pop()));if(!F.default.existsSync(r))throw new Error("FFmpeg binary not found. Please download it first.");return r}catch{return}}var p=c(require("fs")),j=c(require("path"));var le="https://github.com/yt-dlp/yt-dlp/releases/latest/download",T={win32:{x64:"yt-dlp.exe",ia32:"yt-dlp_x86.exe"},linux:{x64:"yt-dlp",armv7l:"yt-dlp_linux_armv7l",aarch64:"yt-dlp_linux_aarch64",arm64:"yt-dlp"},darwin:{x64:"yt-dlp_macos",arm64:"yt-dlp_macos"},android:{arm64:"yt-dlp"}};function ce(){let e=process.platform,r=process.arch;if(!T[e]||!T[e][r])throw new Error(`No FFmpeg build available for ${e} ${r}`);return T[e][r]}async function Y(e){let r=e||d,t=ce(),s=`${le}/${t}`,i=j.join(r,t);if(p.existsSync(i))return i;console.log("Downloading yt-dlp...",s),p.existsSync(r)||p.mkdirSync(r,{recursive:!0});try{await w(s,i),console.log(`yt-dlp downloaded successfully to: ${i}`);try{p.chmodSync(i,493)}catch{console.log("Error while chmod")}return i}catch(a){throw console.error(`Download failed: ${a}`),a}}function L(){let e=process.platform,r=process.arch;try{let t=T[e][r],s=j.join(d,t);if(!p.existsSync(s))throw new Error("Ytdlp binary not found. Please download it first.");return s}catch{return}}var d=G.join(__dirname,"..","bin"),V=class{constructor(r){if(this.binaryPath=r?.binaryPath||L()||"",this.ffmpegPath=r?.ffmpegPath||v(),(!this.binaryPath||!k.existsSync(this.binaryPath))&&console.error(new Error("yt-dlp binary not found. Please install yt-dlp or specify correct binaryPath in options.")),this.ffmpegPath&&!k.existsSync(this.ffmpegPath)&&console.error(new Error(`FFmpeg binary not found at: ${this.ffmpegPath}. Please install FFmpeg or specify correct ffmpegPath.`)),process.platform!=="win32")try{k.chmodSync(this.binaryPath,493)}catch(t){console.error(new Error(`Failed to set executable permissions: ${t instanceof Error?t.message:"Unknown error"}`))}}async checkInstallationAsync(r){return new Promise((t,s)=>{if(r?.ffmpeg&&!this.ffmpegPath)return s(new Error("FFmpeg path is not set"));let i=(0,g.spawn)(this.binaryPath,["--version"]),n=!1,a=!r?.ffmpeg;i.on("error",()=>n=!1),i.on("exit",o=>{if(n=o===0,r?.ffmpeg){let u=(0,g.spawn)(this.ffmpegPath,["-version"]);u.on("error",()=>a=!1),u.on("exit",f=>{a=f===0,t(!!(n&&a))})}else t(!!n)})})}checkInstallation(r){if(r?.ffmpeg&&!this.ffmpegPath)throw new Error("FFmpeg path is not set");let t=(0,g.spawnSync)(this.binaryPath,["--version"],{stdio:"ignore"}),s=r?.ffmpeg?(0,g.spawnSync)(this.ffmpegPath,["-version"],{stdio:"ignore"}):{status:0};return t.status===0&&s.status===0}async execAsync(r,t){let s=this.buildArgs(r,t||{}),i=n=>{if(t?.onData?.(n),t?.onProgress){let a=m(n);a&&t.onProgress?.(a)}};return this._executeAsync(s,i)}exec(r,t){let s=this.buildArgs(r,t||{},!0);return this._execute(s)}_execute(r){let t=(0,g.spawn)(this.binaryPath,r);return t.stderr.on("data",s=>{let i=Buffer.from(s).toString(),n=m(i);n&&t.emit("progress",n)}),t.stdout.on("data",s=>{let i=Buffer.from(s).toString(),n=m(i);n&&t.emit("progress",n)}),t}async _executeAsync(r,t,s){return new Promise((i,n)=>{this.binaryPath||n(new Error("Ytdlp binary not found"));let a=(0,g.spawn)(this.binaryPath,r),o="",u="";a.stdout.on("data",f=>{s||(o+=f.toString(),t?.(Buffer.from(f).toString()))}),a.stderr.on("data",f=>{u+=f.toString(),t?.(Buffer.from(f).toString())}),s&&a.stdout.pipe(s),a.on("close",f=>{f===0?i(o):n(new Error(`yt-dlp exited with code ${f}: ${u}`))}),a.on("error",f=>{n(new Error(`Failed to start yt-dlp process: ${f.message}`))})})}buildArgs(r,t,s,i){let n=x(t);return this.ffmpegPath&&n.push("--ffmpeg-location",this.ffmpegPath),s&&n.push("--progress-template",_),i&&n.push(...i),n.concat(r)}download(r,t){let{format:s,...i}=t||{},n=this.buildArgs(r,i,!0,y(s));return this._execute(n)}async downloadAsync(r,t){let{format:s,onProgress:i,...n}=t||{},a=this.buildArgs(r,n,!!i,y(s));return this._executeAsync(a,o=>{let u=m(o);u&&i?.(u)})}stream(r,t){let{format:s,onProgress:i,...n}=t||{},a=this.buildArgs(r,n,!!i,[...y(s),"-o","-"]),o=new W.PassThrough;return{promise:this._executeAsync(a,f=>{let l=m(f);l&&i?.(l)},o),pipe:(f,l)=>o.pipe(f,l),pipeAsync:(f,l)=>new Promise((I,B)=>{let P=o.pipe(f,l);f.on("finish",()=>I(P)),f.on("error",B)})}}async getInfoAsync(r,t){let s=["--dump-single-json","--quiet",...x({flatPlaylist:!0,...t}),r],i=await this._executeAsync(s);return JSON.parse(i)}async getThumbnailsAsync(r){let t=["--print","thumbnails_table","--print","playlist:thumbnails_table","--quiet",r],s=await this._executeAsync(t);return R(s)}async getTitleAsync(r){let t=["--print","title",r];return await this._executeAsync(t)}async downloadFFmpeg(){return $()}async getFileAsync(r,t){let s=await this.getInfoAsync(r),{format:i,filename:n,metadata:a,onProgress:o,...u}=t||{},f=new W.PassThrough,l=[];f.on("data",E=>l.push(Buffer.from(E)));let I=this.buildArgs(r,u,!!o,[...y(i),"-o","-"]);await this._executeAsync(I,E=>{if(o){let z=m(E);z&&o(z)}},f);let B=new H.Blob(l,{type:A(i)}),P={name:n||`${s.title}.${D(i)}`,type:A(i),size:B.size,...a};return new File([Buffer.concat(l)],P.name,{type:P.type})}async getUrlsAsync(r,t){let s=["--print","urls",...x({flatPlaylist:!0,...t}),r],i=await this._executeAsync(s);return String(i).split(`
`)}},he={downloadFFmpeg:$,findFFmpegBinary:v,PROGRESS_STRING:_,getContentType:A,getFileExtension:D,parseFormatOptions:y,stringToProgress:m,createArgs:x,extractThumbnails:R,downloadFile:w,BIN_DIR:d,downloadYtDlp:Y,findYtdlpBinary:L};0&&(module.exports={BIN_DIR,YtDlp,helpers});
"use strict";var De=Object.create;var E=Object.defineProperty;var Re=Object.getOwnPropertyDescriptor;var Ee=Object.getOwnPropertyNames;var Be=Object.getPrototypeOf,je=Object.prototype.hasOwnProperty;var $e=(e,t)=>{for(var r in t)E(e,r,{get:t[r],enumerable:!0})},re=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Ee(t))!je.call(e,i)&&i!==r&&E(e,i,{get:()=>t[i],enumerable:!(s=Re(t,i))||s.enumerable});return e};var p=(e,t,r)=>(r=e!=null?De(Be(e)):{},re(t||!e||!e.__esModule?E(r,"default",{value:e,enumerable:!0}):r,e)),Me=e=>re(E({},"__esModule",{value:!0}),e);var rt={};$e(rt,{BIN_DIR:()=>m,YtDlp:()=>X,helpers:()=>tt});module.exports=Me(rt);var A=require("child_process"),D=p(require("fs")),Ce=p(require("path"));function g(e){let t=[];if(e.printHelp&&t.push("--help"),e.printVersion&&t.push("--version"),e.update&&t.push("--update"),e.noUpdate&&t.push("--no-update"),e.updateTo&&t.push("--update-to",e.updateTo),e.ignoreErrors&&t.push("--ignore-errors"),e.noAbortOnError&&t.push("--no-abort-on-error"),e.abortOnError&&t.push("--abort-on-error"),e.dumpUserAgent&&t.push("--dump-user-agent"),e.listExtractors&&t.push("--list-extractors"),e.extractorDescriptions&&t.push("--extractor-descriptions"),e.useExtractors&&e.useExtractors.length>0&&t.push("--use-extractors",e.useExtractors.join(",")),e.defaultSearch&&t.push("--default-search",e.defaultSearch),e.ignoreConfig&&t.push("--ignore-config"),e.noConfigLocations&&t.push("--no-config-location"),e.configLocations&&e.configLocations.length>0&&t.push("--config-locations",...e.configLocations),e.pluginDirs&&e.pluginDirs.length>0)for(let s of e.pluginDirs)t.push("--plugin-dirs",s);e.noPluginDirs&&t.push("--no-plugin-dirs"),e.flatPlaylist&&t.push("--flat-playlist"),e.noFlatPlaylist&&t.push("--no-flat-playlist"),e.liveFromStart&&t.push("--live-from-start"),e.noLiveFromStart&&t.push("--no-live-from-start"),e.waitForVideo&&t.push("--wait-for-video",e.waitForVideo.toString()),e.noWaitForVideo&&t.push("--no-wait-for-video"),e.markWatched&&t.push("--mark-watched"),e.noMarkWatched&&t.push("--no-mark-watched"),e.color&&t.push("--color",e.color),e.compatOptions&&e.compatOptions.length>0&&t.push("--compat-options",e.compatOptions.join(",")),e.aliases&&e.aliases.length>0&&t.push("--alias",...e.aliases);let r=e.jsRuntime??"node";if(r&&t.push("--js-runtime",r),e.proxy&&t.push("--proxy",e.proxy),e.socketTimeout&&t.push("--socket-timeout",e.socketTimeout.toString()),e.sourceAddress&&t.push("--source-address",e.sourceAddress),e.impersonate&&e.impersonate.length>0&&t.push("--impersonate",e.impersonate.join(",")),e.listImpersonateTargets&&t.push("--list-impersonate-targets"),e.forceIpv4&&t.push("--force-ipv4"),e.forceIpv6&&t.push("--force-ipv6"),e.enableFileUrls&&t.push("--enable-file-urls"),e.geoVerificationProxy&&t.push("--geo-verification-proxy",e.geoVerificationProxy),e.xff&&t.push("--xff",e.xff),e.playlistItems&&t.push("--playlist-items",e.playlistItems),e.minFilesize&&t.push("--min-filesize",e.minFilesize),e.maxFilesize&&t.push("--max-filesize",e.maxFilesize),e.date&&t.push("--date",e.date),e.dateBefore&&t.push("--datebefore",e.dateBefore),e.dateAfter&&t.push("--dateafter",e.dateAfter),e.matchFilter&&t.push("--match-filter",e.matchFilter),e.noMatchFilters&&t.push("--no-match-filters"),e.breakMatchFilters&&t.push("--break-match-filters",e.breakMatchFilters),e.noBreakMatchFilters&&t.push("--no-break-match-filters"),e.noPlaylist&&t.push("--no-playlist"),e.yesPlaylist&&t.push("--yes-playlist"),e.ageLimit&&t.push("--age-limit",e.ageLimit.toString()),e.downloadArchive&&t.push("--download-archive",e.downloadArchive),e.noDownloadArchive&&t.push("--no-download-archive"),e.maxDownloads&&t.push("--max-downloads",e.maxDownloads.toString()),e.breakOnExisting&&t.push("--break-on-existing"),e.noBreakOnExisting&&t.push("--no-break-on-existing"),e.breakPerInput&&t.push("--break-per-input"),e.noBreakPerInput&&t.push("--break-per-input"),e.skipPlaylistAfterErrors&&t.push("--skip-playlist-after-errors",e.skipPlaylistAfterErrors.toString()),e.concurrentFragments&&t.push("--concurrent-fragments",e.concurrentFragments.toString()),e.limitRate&&t.push("--limit-rate",e.limitRate),e.throttledRate&&t.push("--throttled-rate",e.throttledRate),e.retries&&t.push("--retries",e.retries.toString()),e.fileAccessRetries&&t.push("--file-access-retries",e.fileAccessRetries.toString()),e.fragmentRetries&&t.push("--fragment-retries",e.fragmentRetries.toString()),e.retrySleep&&t.push("--retry-sleep",e.retrySleep.toString()),e.retrySleepByType)for(let[s,i]of Object.entries(e.retrySleepByType))t.push("--retry-sleep",`${s}:${i}`);if(e.skipUnavailableFragments&&t.push("--skip-unavailable-fragments"),e.abortOnUnavailableFragment&&t.push("--abort-on-unavailable-fragment"),e.keepFragments&&t.push("--keep-fragments"),e.noKeepFragments&&t.push("--no-keep-fragments"),e.bufferSize&&t.push("--buffer-size",e.bufferSize),e.resizeBuffer&&t.push("--resize-buffer"),e.noResizeBuffer&&t.push("--no-resize-buffer"),e.httpChunkSize&&t.push("--http-chunk-size",e.httpChunkSize),e.playlistRandom&&t.push("--playlist-random"),e.lazyPlaylist&&t.push("--lazy-playlist"),e.noLazyPlaylist&&t.push("--no-lazy-playlist"),e.xattrSetFilesize&&t.push("--xattr-set-filesize"),e.hlsUseMpegts&&t.push("--hls-use-mpegts"),e.noHlsUseMpegts&&t.push("--no-hls-use-mpegts"),e.downloadSections&&t.push("--download-sections",e.downloadSections.toString()),e.downloader&&t.push("--downloader",e.downloader),e.downloaderArgs&&t.push("--downloader-args",e.downloaderArgs),e.batchFile&&t.push("--batch-file",e.batchFile),e.noBatchFile&&t.push("--no-batch-file"),e.paths)if(typeof e.paths=="string")t.push("--paths",e.paths);else for(let[s,i]of Object.entries(e.paths))t.push("--paths",`${s}:${i}`);if(e.output&&t.push("-o",e.output),e.outputNaPlaceholder&&t.push("--output-na-placeholder",e.outputNaPlaceholder),e.restrictFilenames&&t.push("--restrict-filenames"),e.noRestrictFilenames&&t.push("--no-restrict-filenames"),e.windowsFilenames&&t.push("--windows-filenames"),e.noWindowsFilenames&&t.push("--no-windows-filenames"),e.trimFileNames&&t.push("--trim-file-names",e.trimFileNames.toString()),e.noOverwrites&&t.push("--no-overwrites"),e.forceOverwrites&&t.push("--force-overwrites"),e.noForceOverwrites&&t.push("--no-force-overwrites"),e.continue&&t.push("--continue"),e.noContinue&&t.push("--no-continue"),e.part&&t.push("--part"),e.noPart&&t.push("--no-part"),e.mtime&&t.push("--mtime"),e.noMtime&&t.push("--no-mtime"),e.writeDescription&&t.push("--write-description"),e.noWriteDescription&&t.push("--no-write-description"),e.writeInfoJson&&t.push("--write-info-json"),e.noWriteInfoJson&&t.push("--no-write-info-json"),e.writePlaylistMetafiles&&t.push("--write-playlist-metafiles"),e.noWritePlaylistMetafiles&&t.push("--no-write-playlist-metafiles"),e.cleanInfoJson&&t.push("--clean-info-json"),e.noCleanInfoJson&&t.push("--no-clean-info-json"),e.writeComments&&t.push("--write-comments"),e.noWriteComments&&t.push("--no-write-comments"),e.loadInfoJson&&t.push("--load-info-json",e.loadInfoJson.toString()),e.cookies&&t.push("--cookies",e.cookies),e.noCookies&&t.push("--no-cookies"),e.cookiesFromBrowser&&t.push("--cookies-from-browser",e.cookiesFromBrowser),e.noCookiesFromBrowser&&t.push("--no-cookies-from-browser"),e.cacheDir&&t.push("--cache-dir",e.cacheDir),e.noCacheDir&&t.push("--no-cache-dir"),e.rmCacheDir&&t.push("--rm-cache-dir"),e.writeThumbnail&&t.push("--write-thumbnail"),e.noWriteThumbnails&&t.push("--no-write-thumbnails"),e.writeAllThumbnails&&t.push("--write-all-thumbnails"),e.listThumbnails&&t.push("--list-thumbnails"),e.writeLink&&t.push("--write-link"),e.writeUrlLink&&t.push("--write-url-link"),e.writeWeblocLink&&t.push("--write-webloc-link"),e.writeDesktopLink&&t.push("--write-desktop-link"),e.quiet&&t.push("--quiet"),e.noQuiet&&t.push("--no-quiet"),e.noWarnings&&t.push("--no-warnings"),e.simulate&&t.push("--simulate"),e.noSimulate&&t.push("--no-simulate"),e.ignoreNoFormatsError&&t.push("--ignore-no-formats-error"),e.noIgnoreNoFormatsError&&t.push("--no-ignore-no-formats-error"),e.skipDownload&&t.push("--skip-download"),e.print&&t.push("--print",e.print),e.printToFile&&t.push("--print-to-file",e.printToFile),e.dumpJson&&t.push("--dump-json"),e.dumpSingleJson&&t.push("--dump-single-json"),e.forceWriteArchive&&t.push("--force-write-archive"),e.newline&&t.push("--newline"),e.noProgress&&t.push("--no-progress"),e.progress&&t.push("--progress"),e.consoleTitle&&t.push("--console-title"),e.progressTemplate&&t.push("--progress-template",e.progressTemplate),e.progressDelta&&t.push("--progress-delta",e.progressDelta.toString()),e.verbose&&t.push("--verbose"),e.dumpPages&&t.push("--dump-pages"),e.writePages&&t.push("--write-pages"),e.printTraffic&&t.push("--print-traffic"),e.encoding&&t.push("--encoding",e.encoding),e.legacyServerConnect&&t.push("--legacy-server-connect"),e.noCheckCertificates&&t.push("--no-check-certificates"),e.preferInsecure&&t.push("--prefer-insecure"),e.addHeaders)for(let[s,i]of Object.entries(e.addHeaders))t.push("--add-header",`${s}:${i}`);if(e.headers)for(let[s,i]of Object.entries(e.headers))t.push("--add-header",`${s}:${i}`);if(e.bidiWorkaround&&t.push("--bidi-workaround"),e.sleepRequests&&t.push("--sleep-requests",e.sleepRequests.toString()),e.sleepInterval&&t.push("--sleep-interval",e.sleepInterval.toString()),e.maxSleepInterval&&t.push("--max-sleep-interval",e.maxSleepInterval.toString()),e.sleepSubtitles&&t.push("--sleep-subtitles",e.sleepSubtitles.toString()),e.format&&t.push("-f",e.format),e.formatSort&&e.formatSort.length>0&&t.push("--format-sort",e.formatSort.join(",")),e.formatSortForce&&t.push("--format-sort-force"),e.noFormatSortForce&&t.push("--no-format-sort-force"),e.videoMultiStreams&&t.push("--video-multistreams"),e.noVideoMultiStreams&&t.push("--no-video-multistreams"),e.audioMultiStreams&&t.push("--audio-multistreams"),e.noAudioMultiStreams&&t.push("--no-audio-multistreams"),e.preferFreeFormats&&t.push("--prefer-free-formats"),e.noPreferFreeFormats&&t.push("--no-prefer-free-formats"),e.checkFormats&&t.push("--check-formats"),e.checkAllFormats&&t.push("--check-all-formats"),e.noCheckFormats&&t.push("--no-check-formats"),e.listFormats&&t.push("--list-formats"),e.mergeOutputFormat&&t.push("--merge-output-format",e.mergeOutputFormat),e.writeSubs&&t.push("--write-subs"),e.noWriteSubs&&t.push("--no-write-subs"),e.writeAutoSubs&&t.push("--write-auto-subs"),e.writeAllSubs&&t.push("--all-subs"),e.listSubs&&t.push("--list-subs"),e.subFormat&&t.push("--sub-format",e.subFormat),e.subLangs&&e.subLangs.length>0&&t.push("--sub-langs",e.subLangs.join(",")),e.username&&t.push("--username",e.username),e.password&&t.push("--password",e.password),e.twoFactor&&t.push("--twofactor",e.twoFactor),e.netrc&&t.push("--netrc"),e.videoPassword&&t.push("--video-password",e.videoPassword),e.apMso&&t.push("--ap-mso",e.apMso),e.apUsername&&t.push("--ap-username",e.apUsername),e.apPassword&&t.push("--ap-password",e.apPassword),e.netrcLocation&&t.push("--netrc-location",e.netrcLocation),e.netrcCmd&&t.push("--netrc-cmd",e.netrcCmd),e.apListMso&&t.push("--ap-list-mso"),e.clientCertificate&&t.push("--client-certificate",e.clientCertificate),e.clientCertificateKey&&t.push("--client-certificate-key",e.clientCertificateKey),e.clientCertificatePassword&&t.push("--client-certificate-password",e.clientCertificatePassword),e.extractorRetries!==void 0&&t.push("--extractor-retries",e.extractorRetries.toString()),e.allowDynamicMpd&&t.push("--allow-dynamic-mpd"),e.ignoreDynamicMpd&&t.push("--ignore-dynamic-mpd"),e.hlsSplitDiscontinuity&&t.push("--hls-split-discontinuity"),e.noHlsSplitDiscontinuity&&t.push("--no-hls-split-discontinuity"),e.extractorArgs)for(let[s,i]of Object.entries(e.extractorArgs))t.push("--extractor-args",`${s}:${i.join(" ")}`);if(e.playlistStart!==void 0&&t.push("--playlist-start",e.playlistStart.toString()),e.playlistEnd!==void 0&&t.push("--playlist-end",e.playlistEnd.toString()),e.matchTitle&&t.push("--match-title",e.matchTitle),e.rejectTitle&&t.push("--reject-title",e.rejectTitle),e.includeAds&&t.push("--include-ads"),e.breakOnReject&&t.push("--break-on-reject"),e.noDownload&&t.push("--no-download"),e.playlistReverse&&t.push("--playlist-reverse"),e.geoBypass&&t.push("--geo-bypass"),e.geoBypassCountry&&t.push("--geo-bypass-country",e.geoBypassCountry),e.geoBypassIpBlock&&t.push("--geo-bypass-ip-block",e.geoBypassIpBlock),e.convertThumbnails&&t.push("--convert-thumbnails",e.convertThumbnails),e.writeLink&&t.push("--write-link"),e.writeUrlLink&&t.push("--write-url-link"),e.writeWeblocLink&&t.push("--write-webloc-link"),e.writeLnkLink&&t.push("--write-lnk-link"),e.referer&&t.push("--referer",e.referer),e.userAgent&&t.push("--user-agent",e.userAgent),e.extractAudio&&t.push("--extract-audio"),e.audioFormat&&t.push("--audio-format",e.audioFormat),e.audioQuality&&t.push("--audio-quality",e.audioQuality),e.remuxVideo&&t.push("--remux-video",e.remuxVideo),e.recodeVideo&&t.push("--recode-video",e.recodeVideo),e.postprocessorArgs)for(let[s,i]of Object.entries(e.postprocessorArgs))t.push("--postprocessor-args",`${s}:${i.join(" ")}`);if(e.keepVideo&&t.push("--keep-video"),e.noKeepVideo&&t.push("--no-keep-video"),e.postOverwrites&&t.push("--post-overwrites"),e.noPostOverwrites&&t.push("--no-post-overwrites"),e.embedSubs&&t.push("--embed-subs"),e.noEmbedSubs&&t.push("--no-embed-subs"),e.embedThumbnail&&t.push("--embed-thumbnail"),e.noEmbedThumbnail&&t.push("--no-embed-thumbnail"),e.embedMetadata&&t.push("--embed-metadata"),e.noEmbedMetadata&&t.push("--no-embed-metadata"),e.embedChapters&&t.push("--embed-chapters"),e.noEmbedChapters&&t.push("--no-embed-chapters"),e.embedInfoJson&&t.push("--embed-info-json"),e.noEmbedInfoJson&&t.push("--no-embed-info-json"),e.parseMetadata)for(let[s,i]of Object.entries(e.parseMetadata))t.push("--parse-metadata",`${s}:${i}`);if(e.replaceInMetadata)for(let[s,[i,n]]of Object.entries(e.replaceInMetadata))t.push("--replace-in-metadata",`${s} ${i} ${n}`);if(e.xattrs&&t.push("--xattrs"),e.concatPlaylist&&t.push("--concat-playlist",e.concatPlaylist),e.fixup&&t.push("--fixup",e.fixup),e.ffmpegLocation&&t.push("--ffmpeg-location",e.ffmpegLocation),e.exec&&t.push("--exec",e.exec),e.noExec&&t.push("--no-exec"),e.convertSubs&&t.push("--convert-subs",e.convertSubs),e.convertThumbnails&&t.push("--convert-thumbnails",e.convertThumbnails),e.splitChapters&&t.push("--split-chapters"),e.noSplitChapters&&t.push("--no-split-chapters"),e.removeChapters&&t.push("--remove-chapters",e.removeChapters),e.noRemoveChapters&&t.push("--no-remove-chapters"),e.forceKeyframesAtCuts&&t.push("--force-keyframes-at-cuts"),e.noForceKeyframesAtCuts&&t.push("--no-force-keyframes-at-cuts"),e.usePostProcessor&&e.usePostProcessor.length>0)for(let s of e.usePostProcessor)t.push("--use-postprocessor",s);return e.sponsorblockMark&&e.sponsorblockMark.length>0&&t.push("--sponsorblock-mark",e.sponsorblockMark.join(",")),e.sponsorblockRemove&&e.sponsorblockRemove.length>0&&t.push("--sponsorblock-remove",e.sponsorblockRemove.join(",")),e.sponsorblockChapterTitle&&t.push("--sponsorblock-chapter-title",e.sponsorblockChapterTitle),e.noSponsorblock&&t.push("--no-sponsorblock"),e.sponsorblockApi&&t.push("--sponsorblock-api",e.sponsorblockApi),e.additionalOptions&&e.additionalOptions.length>0&&t.push(...e.additionalOptions),e.rawArgs&&e.rawArgs.length>0&&t.push(...e.rawArgs),t}function B(e){let t=[],r=e.split(`
`).slice(1);for(let s of r){let i=s.match(/(\d+)\s+(\S+)\s+(\S+)\s+(https:\/\/[\S]+)/);i&&t.push({id:parseInt(i[1],10),width:i[2]==="unknown"?"unknown":parseInt(i[2],10),height:i[3]==="unknown"?"unknown":parseInt(i[3],10),url:i[4]})}return t}var se={"2160p":"bv*[height<=2160]","1440p":"bv*[height<=1440]","1080p":"bv*[height<=1080]","720p":"bv*[height<=720]","480p":"bv*[height<=480]","360p":"bv*[height<=360]","240p":"bv*[height<=240]","144p":"bv*[height<=133]",highest:"bv*",lowest:"wv*"};function x(e){if(!e)return[];if(typeof e=="string")return["-f",e];if(Object.keys(e).length===0)return["-f","bv*+ba"];let t=[],{filter:r,quality:s,type:i}=e;return r==="audioonly"&&(t=["-x","--audio-format",i||"mp3","--audio-quality",s?s.toString():"5"]),r==="videoonly"&&(t=["-f",(s?se[s]:"bv*")+"[acodec=none]"]),r==="audioandvideo"&&(t=["-f",(s=="lowest"?"w*":"b*")+"[vcodec!=none][acodec!=none][ext="+(i||"mp4")+"]"]),r==="mergevideo"&&(t=["-f",`${s?se[s]:"bv*"}+ba`],i&&t.push("--merge-output-format",i)),t}function j(e){if(!e||typeof e=="string")return"video/mp4";let{filter:t,type:r}=e;switch(t){case"videoonly":case"audioandvideo":switch(r){case"mp4":return"video/mp4";case"webm":return"video/webm";default:return"video/mp4"}case"audioonly":switch(r){case"aac":return"audio/aac";case"flac":return"audio/flac";case"mp3":return"audio/mp3";case"m4a":return"audio/mp4";case"opus":return"audio/opus";case"vorbis":return"audio/vorbis";case"wav":return"audio/wav";case"alac":return"audio/mp4";default:return"audio/mpeg"}case"mergevideo":switch(r){case"webm":return"video/webm";case"mkv":return"video/x-matroska";case"ogg":return"video/ogg";case"flv":return"video/x-flv";default:return"video/mp4"}}}function ie(e){if(!e||typeof e=="string")return"mp4";let{filter:t,type:r}=e;return r||(t==="audioonly"?"mp3":"mp4")}function ne(e){if(!e?.extractAudio)return null;switch(e.audioFormat||"mp3"){case"aac":return"audio/aac";case"flac":return"audio/flac";case"mp3":return"audio/mpeg";case"m4a":return"audio/mp4";case"opus":return"audio/opus";case"vorbis":return"audio/vorbis";case"wav":return"audio/wav";case"alac":return"audio/mp4";default:return"audio/mpeg"}}var $="~ytdlp-progress-%(progress)#j";function L(e,t=2){let r=Number(e);if(r===0||isNaN(r))return r+" Bytes";let s=1024,i=t<0?0:t,n=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],a=Math.floor(Math.log(r)/Math.log(s));return parseFloat((r/Math.pow(s,a)).toFixed(i))+" "+n[a]}function Ve(e,t,r){let s=Math.pow(r||10,t);return Math.round(e*s)/s}function _e(e){e=Number(e);let t=Math.floor(e/3600),r=Math.floor(e%3600/60),s=Math.floor(e%3600%60),i=t>0?t+(t==1?" hour, ":" hours, "):"",n=r>0?r+(r==1?" minute, ":" minutes, "):"",a=s>=0?s+(s==1?" second":" seconds"):"";return i+n+a}function y(e){try{if(!e.includes("~ytdlp-progress-"))throw new Error;let t=e.trim().replace("~ytdlp-progress-","");if(!t)throw new Error;let r=JSON.parse(t),s=f=>{if(f==null||f==="NA")return;let c=Number(f);return isNaN(c)?void 0:c},i=s(r.downloaded_bytes),n=s(r.total_bytes)??s(r.total_bytes_estimate),a=s(r.speed),o=s(r.eta),u=i!==void 0&&n!==void 0&&n>0?Ve(100*i/n,2):void 0;return{filename:r.filename,status:r.status,downloaded:i,downloaded_str:i!==void 0?L(i):void 0,total:n,total_str:n!==void 0?L(n):void 0,speed:a,speed_str:a!==void 0?L(a)+"/s":void 0,eta:o,eta_str:o!==void 0?_e(o):void 0,percentage:u,percentage_str:u!==void 0?u+"%":void 0}}catch{return}}var M=p(require("path")),O=p(require("fs"));var Ne=p(require("https")),We=p(require("http")),Y=require("url"),b=p(require("fs"));function U(e,t={}){return new Promise((r,s)=>{let a=(new Y.URL(e).protocol==="https:"?Ne:We).get(e,t,o=>{if(o.statusCode>=300&&o.statusCode<400&&o.headers.location){let u=new Y.URL(o.headers.location,e).toString();U(u,t).then(r).catch(s);return}r(o)});a.on("error",s),a.setTimeout(3e4,()=>{a.destroy(),s(new Error("Request timed out"))})})}async function v(e,t){try{let r=b.createWriteStream(t),s=await U(e);if(s.statusCode!==200)throw r.close(),b.unlinkSync(t),new Error(`Failed to download file: ${s.statusCode} ${s.statusMessage}`);let i=parseInt(s.headers["content-length"]||"0",10),n=0;return s.on("data",a=>{n+=a.length;let o=n/i*100;process.stdout.write(`Progress: ${Math.round(o)}%\r`)}),s.pipe(r),new Promise((a,o)=>{r.on("finish",()=>{r.close(),console.log(`
Download complete!`),a()}),r.on("error",u=>{r.close(),b.unlinkSync(t),o(u)}),s.on("error",u=>{r.close(),b.unlinkSync(t),o(u)})})}catch(r){throw b.existsSync(t)&&b.unlinkSync(t),r}}async function ae(e,t={}){let r=await U(e,t);if(r.statusCode!==200)throw new Error(`Failed to fetch text: ${r.statusCode} ${r.statusMessage}`);return new Promise((s,i)=>{let n="";r.setEncoding("utf8"),r.on("data",a=>{n+=a}),r.on("end",()=>s(n)),r.on("error",i)})}var oe=p(require("fs")),S=p(require("path"));function Le(e){let t=e;for(;;){if(oe.existsSync(S.join(t,"package.json")))return t;let r=S.dirname(t);if(r===t)return e;t=r}}var ue=Le(__dirname),m=S.join(ue,"bin"),ht=S.join(ue,"package.json");var Ye="https://github.com/iqbal-rashed/ytdlp-nodejs/releases/download/ffmpeg-latest",z={win32:{x64:["win-x64-ffmpeg.exe","win-x64-ffprobe.exe"],ia32:["win-ia32-ffmpeg.exe","win-ia32-ffprobe.exe"],arm64:["win-arm64-ffmpeg.exe","win-arm64-ffprobe.exe"]},linux:{x64:["linux-x64-ffmpeg","linux-x64-ffprobe"],arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]},darwin:{x64:["macos-x64-ffmpeg","macos-x64-ffprobe"],arm64:["macos-arm64-ffmpeg","macos-arm64-ffprobe"]},android:{arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]}};function fe(){let e=process.platform,t=process.arch;if(!z[e]||!z[e][t])throw new Error(`No FFmpeg build available for platform: ${e}, architecture: ${t}`);return z[e][t]}async function K(e){let t=e||m,r=C();if(r)return r;try{let s=fe();if(!s.length)throw new Error;let i=s.map(a=>`${Ye}/${a}`),n=s.map(a=>M.default.join(t,String(a.split("-").pop())));O.default.existsSync(t)||O.default.mkdirSync(t,{recursive:!0}),console.log("Downloading FFmpeg and FFprobe...");for(let a=0;a<s.length;a++){let o=i[a],u=n[a];console.log("Downloading...",M.default.basename(o)),await v(o,u)}try{for(let a of n)O.default.chmodSync(a,493)}catch{console.log("Note: Could not set executable permissions (likely Windows)")}return C()}catch(s){throw console.error(`Download failed: ${s}`),s}}function C(){try{let e=fe();if(!e.length)throw new Error;let t=M.default.join(m,String(e[0].split("-").pop()));if(!O.default.existsSync(t))throw new Error("FFmpeg binary not found. Please download it first.");return t}catch{return}}var h=p(require("fs")),T=p(require("path"));var le=p(require("crypto")),ce="https://github.com/yt-dlp/yt-dlp/releases/latest/download",V={win32:{x64:"yt-dlp.exe",ia32:"yt-dlp_x86.exe"},linux:{x64:"yt-dlp",armv7l:"yt-dlp_linux_armv7l",aarch64:"yt-dlp_linux_aarch64",arm64:"yt-dlp"},darwin:{x64:"yt-dlp_macos",arm64:"yt-dlp_macos"},android:{arm64:"yt-dlp"}};function Ue(){let e=process.platform,t=process.arch;if(!V[e]||!V[e][t])throw new Error(`No yt-dlp build available for ${e} ${t}`);return V[e][t]}async function _(e){let t=e||m,r=Ue(),s=`${ce}/${r}`,i=T.join(t,r);if(h.existsSync(i))return i;console.log("Downloading yt-dlp...",s),h.existsSync(t)||h.mkdirSync(t,{recursive:!0});try{await v(s,i),console.log(`yt-dlp downloaded successfully to: ${i}`);try{h.chmodSync(i,493)}catch{console.log("Error while chmod")}return i}catch(a){throw console.error(`Download failed: ${a}`),a}}async function ze(e){return new Promise((t,r)=>{let s=le.default.createHash("sha256"),i=h.createReadStream(e);i.on("data",n=>s.update(n)),i.on("end",()=>t(s.digest("hex"))),i.on("error",r)})}async function Ke(e){try{let s=(await ae(`${ce}/SHA2-256SUMS`)).split(/\r?\n/).find(n=>n.includes(e));if(!s)return;let[i]=s.trim().split(/\s+/);return i||void 0}catch{return}}async function J(e){let t=await _(e),r=T.basename(t),s=await Ke(r);if(!s)return{path:t,verified:!1};let i=await ze(t);if(i.toLowerCase()!==s.toLowerCase())throw new Error(`Checksum mismatch for ${r}. Expected ${s}, got ${i}`);return{path:t,verified:!0,checksum:s}}function q(){let e=process.platform,t=process.arch;try{let r=V[e][t],s=T.join(m,r);if(!h.existsSync(s))throw new Error("Ytdlp binary not found. Please download it first.");return s}catch{return}}function P({url:e,options:t,ffmpegPath:r,withProgressTemplate:s,extra:i}){let n=g(t||{});return r&&n.push("--ffmpeg-location",r),s&&n.push("--progress-template",$),i&&i.length>0&&n.push(...i),e&&n.push(e),n}var G=require("child_process");var I=class extends Error{constructor(t,r={}){super(t),this.name="YtDlpError",this.exitCode=r.exitCode,this.stdout=r.stdout,this.stderr=r.stderr,this.args=r.args,this.hint=r.hint}};var Je="yt-dlp reported a missing JavaScript runtime. Install Node.js or a supported browser runtime for full YouTube support. See README troubleshooting for details.";function de(e){let t=e.toLowerCase();if(t.includes("javascript runtime")||t.includes("js runtime")||t.includes("node.js")||t.includes("nodejs")||t.includes("phantomjs")||t.includes("chromium")||t.includes("firefox"))return Je}function N(e,t,r){let s=y(e);s&&(t?.(s),r?.(s))}function W(e,t,r={}){r.debugPrintCommandLine&&console.error(`[ytdlp-nodejs] Command: ${e} ${t.join(" ")}`);let s=(0,G.spawn)(e,t,{shell:!1});return s.stdout.on("data",i=>{N(Buffer.from(i).toString(),void 0,n=>s.emit("progress",n))}),s.stderr.on("data",i=>{N(Buffer.from(i).toString(),void 0,n=>s.emit("progress",n))}),s}function d(e,t,r={}){return new Promise((s,i)=>{r.debugPrintCommandLine&&console.error(`[ytdlp-nodejs] Command: ${e} ${t.join(" ")}`);let n=(0,G.spawn)(e,t,{shell:!1}),a="",o="";r.passThrough&&n.stdout.pipe(r.passThrough),n.stdout.on("data",u=>{if(r.passThrough)return;let f=Buffer.from(u).toString();a+=f,r.onStdout?.(f),N(f,r.onProgress)}),n.stderr.on("data",u=>{let f=Buffer.from(u).toString();o+=f,r.onStderr?.(f),N(f,r.onProgress)}),n.on("close",u=>{if(u===0)s({stdout:a,stderr:o,exitCode:u});else{let f=de(o);i(new I(`yt-dlp exited with code ${u}: ${o}`,{exitCode:u??void 0,stdout:a,stderr:o,args:t,hint:f}))}}),n.on("error",u=>{i(new I(`Failed to start yt-dlp process: ${u.message}`,{args:t}))})})}function pe(e){return e.split(/\r?\n/).map(t=>t.trim()).filter(t=>t.length>0).filter(t=>!t.includes("~ytdlp-progress-"))}var qe=[".jpg",".jpeg",".png",".webp",".gif"],Ge=[".vtt",".srt",".ass",".ssa",".sub",".lrc"];function me(e){let t=[],r=[],s=[];for(let i of e){let n=i.toLowerCase();qe.some(a=>n.endsWith(a))?r.push(i):Ge.some(a=>n.endsWith(a))?s.push(i):t.push(i)}return{filePaths:t,thumbnailPaths:r,subtitlePaths:s}}function he(e){return P({url:e.url,options:e.options,ffmpegPath:e.ffmpegPath,withProgressTemplate:e.withProgressTemplate,extra:e.extra})}function ge(e){let t=x(e);return t.push("--print","after_move:filepath"),t}function He(e,t){if(!e.stdout)return;let r=[],s="";e.stdout.on("data",i=>{s+=i.toString();let n=s.split(/\r?\n/);s=n.pop()||"";for(let a of n){let o=a.trim();!o||o.includes("~ytdlp-progress-")||r.push(o)}}),e.on("close",()=>{let i=s.trim();if(i&&!i.includes("~ytdlp-progress-")&&r.push(i),r.length>0){let n=me(r);e.emit("paths",n)}t?.(r)})}function Qe(e,t){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return W(e.binaryPath,t)}async function Xe(e,t,r,s){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return(await d(e.binaryPath,t,{onStdout:r,onStderr:r,passThrough:s})).stdout}async function Ze(e,t,r){let{format:s,onProgress:i,onPaths:n,...a}=r||{},o=ge(s),u=he({url:t,options:a,ffmpegPath:e.ffmpegPath,withProgressTemplate:!!i,extra:o}),f=await Xe(e,u,k=>{let w=y(k);w&&i?.(w)}),c=pe(f);return n?.(c),{output:f,paths:c}}function ye(e,t,r){let{format:s,onPaths:i,...n}=r||{},a=ge(s),o=he({url:t,options:n,ffmpegPath:e.ffmpegPath,withProgressTemplate:!0,extra:a}),u=Qe(e,o);return He(u,i),u}async function be(e,t,r){let s=await Ze(e,t,r),{filePaths:i,thumbnailPaths:n,subtitlePaths:a}=me(s.paths);return{output:s.output,filePaths:i,thumbnailPaths:n,subtitlePaths:a}}var H=require("stream");async function et(e,t,r,s){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return(await d(e.binaryPath,t,{passThrough:s,onProgress:r})).stdout}function we(e,t,r){let{format:s,onProgress:i,...n}=r||{},a=P({url:t,options:n,ffmpegPath:e.ffmpegPath,withProgressTemplate:!!i,extra:[...x(s),"-o","-"]}),o=new H.PassThrough;return{promise:et(e,a,i,o),pipe:(f,c)=>o.pipe(f,c),pipeAsync:(f,c)=>new Promise((k,w)=>{let Z=o.pipe(f,c);f.on("finish",()=>k(Z)),f.on("error",w)})}}async function xe(e,t,r){let{format:s,filename:i,metadata:n,onProgress:a,...o}=r||{},u="";if(!i)try{u=(await d(e.binaryPath,["--print","%(title)s","--no-download",t])).stdout.trim()}catch{}let f=new H.PassThrough,c=[];f.on("data",R=>{c.push(Buffer.from(R))});let k=P({url:t,options:o,ffmpegPath:e.ffmpegPath,withProgressTemplate:!!a,extra:[...x(s),"-o","-"]});if(!e.binaryPath)throw new Error("Ytdlp binary not found");await d(e.binaryPath,k,{onStderr:R=>{if(a){let te=y(R);te&&a(te)}},passThrough:f});let w=ne(o)||j(s)||"video/mp4",Te={"video/mp4":"mp4","video/webm":"webm","video/mkv":"mkv","audio/mp3":"mp3","audio/mpeg":"mp3","audio/m4a":"m4a","audio/aac":"aac","audio/flac":"flac","audio/wav":"wav","audio/ogg":"ogg","audio/opus":"opus"}[w]||w.split("/")[1]||"mp4",Ie=u?`${u}.${Te}`:"",ee={name:i||Ie||"download",type:w,size:Buffer.concat(c).length,...n};return new File([new Uint8Array(Buffer.concat(c))],ee.name,{type:ee.type})}function Q(e){let t=e.trim();if(!t)throw new Error("Empty JSON output from yt-dlp.");return JSON.parse(t)}async function F(e,t){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return(await d(e.binaryPath,t)).stdout}async function Pe(e,t,r){let s=["--dump-single-json","--quiet",...g({flatPlaylist:!0,...r}),t],i=await F(e,s);return Q(i)}async function Fe(e,t,r){let s=["--dump-single-json","--quiet",...g({flatPlaylist:!0,...r}),t],i=await F(e,s),n=Q(i),a=n.formats||[];return{source:"json",info:n,formats:a}}async function ve(e,t,r){let s=["--get-url",...g(r||{}),t],i=await F(e,s);return String(i).split(/\r?\n/).map(n=>n.trim()).filter(n=>n.length>0)}async function Se(e,t){let s=await F(e,["--print","thumbnails_table","--print","playlist:thumbnails_table","--quiet",t]);return B(s)}async function Ae(e,t){return await F(e,["--print","title",t])}async function ke(e){return(await F(e,["--version"])).trim()}async function Oe(e,t,r){let s=["--print","urls",...g({flatPlaylist:!0,...r}),t],i=await F(e,s);return String(i).split(`
`)}var X=class{constructor(t){if(this.binaryPath=t?.binaryPath||q()||"",this.ffmpegPath=t?.ffmpegPath||C(),(!this.binaryPath||!D.existsSync(this.binaryPath))&&console.error(new Error("yt-dlp binary not found. Please install yt-dlp or specify correct binaryPath in options.")),this.ffmpegPath&&!D.existsSync(this.ffmpegPath)&&console.error(new Error(`FFmpeg binary not found at: ${this.ffmpegPath}. Please install FFmpeg or specify correct ffmpegPath.`)),process.platform!=="win32"&&this.binaryPath&&this.binaryPath.startsWith(m))try{D.chmodSync(this.binaryPath,493)}catch{}}getDownloadContext(){return{binaryPath:this.binaryPath,ffmpegPath:this.ffmpegPath}}getStreamContext(){return{binaryPath:this.binaryPath,ffmpegPath:this.ffmpegPath}}getInfoContext(){return{binaryPath:this.binaryPath}}async checkInstallationAsync(t){return new Promise((r,s)=>{if(t?.ffmpeg&&!this.ffmpegPath)return s(new Error("FFmpeg path is not set"));let i=(0,A.spawn)(this.binaryPath,["--version"]),n=!1,a=!t?.ffmpeg;i.on("error",()=>n=!1),i.on("exit",o=>{if(n=o===0,t?.ffmpeg){let u=(0,A.spawn)(this.ffmpegPath,["-version"]);u.on("error",()=>a=!1),u.on("exit",f=>{a=f===0,r(n&&a)})}else r(n)})})}checkInstallation(t){if(t?.ffmpeg&&!this.ffmpegPath)throw new Error("FFmpeg path is not set");let r=(0,A.spawnSync)(this.binaryPath,["--version"],{stdio:"ignore"}),s=t?.ffmpeg?(0,A.spawnSync)(this.ffmpegPath,["-version"],{stdio:"ignore"}):{status:0};return r.status===0&&s.status===0}async execAsync(t,r){let s=this.buildArgs(t,r||{}),i=n=>{if(r?.onData?.(n),r?.onProgress){let a=y(n);a&&r.onProgress?.(a)}};return this._executeAsync(s,i)}exec(t,r){let s=this.buildArgs(t,r||{},!0);return this._execute(s)}_execute(t){return W(this.binaryPath,t)}async _executeAsync(t,r){if(!this.binaryPath)throw new Error("Ytdlp binary not found");return(await d(this.binaryPath,t,{onStdout:r,onStderr:r})).stdout}buildArgs(t,r,s,i){return P({url:t,options:r,ffmpegPath:this.ffmpegPath,withProgressTemplate:s,extra:i})}download(t,r){return ye(this.getDownloadContext(),t,r)}async downloadAsync(t,r){return be(this.getDownloadContext(),t,r)}stream(t,r){return we(this.getStreamContext(),t,r)}async getInfoAsync(t,r){return Pe(this.getInfoContext(),t,r)}async downloadAudio(t,r="mp3",s){let i=["aac","flac","mp3","m4a","opus","vorbis","wav","alac"];if(!i.includes(r))throw new Error(`Invalid audio format: ${r}. Supported: ${i.join(", ")}`);return this.downloadAsync(t,{...s,extractAudio:!0,audioFormat:r})}async downloadVideo(t,r="best",s){let i=["best","2160p","1440p","1080p","720p","480p","360p","240p","144p","highest","lowest"];if(!i.includes(r))throw new Error(`Invalid video quality: ${r}. Supported: ${i.join(", ")}`);let n=r==="best"?"bestvideo+bestaudio/best":`bestvideo[height<=${parseInt(r)||1080}]+bestaudio/best[height<=${parseInt(r)||1080}]`;return this.downloadAsync(t,{...s,format:n})}async getSubtitles(t,r){return(await this.downloadAsync(t,{...r,listSubs:!0,skipDownload:!0})).output?[]:[]}async getComments(t,r=20,s){let i=await this.downloadAsync(t,{...s,writeComments:!0,dumpSingleJson:!0,skipDownload:!0,extractorArgs:{youtube:[`max_comments=${r}`,"player_skip=webpage"]}});try{return JSON.parse(i.output).comments||[]}catch{return[]}}async getDirectUrlsAsync(t,r){return ve(this.getInfoContext(),t,r)}async getFormatsAsync(t,r){return Fe(this.getInfoContext(),t,r)}async getThumbnailsAsync(t){return Se(this.getInfoContext(),t)}async getTitleAsync(t){return Ae(this.getInfoContext(),t)}async getVersionAsync(){return ke(this.getInfoContext())}async downloadFFmpeg(){return K()}async getFileAsync(t,r){return xe(this.getStreamContext(),t,r)}async getUrlsAsync(t,r){return Oe(this.getInfoContext(),t,r)}async updateYtDlpAsync(t){if(t?.preferBuiltIn!==!1&&this.binaryPath)try{await d(this.binaryPath,["--update"]);let o=await this.getVersionAsync().catch(()=>{});return{method:"built-in",binaryPath:this.binaryPath,version:o}}catch{}let s=t?.outDir||(this.binaryPath?Ce.default.dirname(this.binaryPath):void 0);if(t?.verifyChecksum!==!1){let o=await J(s),u=await d(o.path,["--version"]).then(f=>f.stdout.trim()).catch(()=>{});return{method:"download",binaryPath:o.path,version:u,verified:o.verified}}let n=await _(s),a=await d(n,["--version"]).then(o=>o.stdout.trim()).catch(()=>{});return{method:"download",binaryPath:n,version:a,verified:!1}}},tt={downloadFFmpeg:K,findFFmpegBinary:C,PROGRESS_STRING:$,getContentType:j,getFileExtension:ie,parseFormatOptions:x,stringToProgress:y,createArgs:g,extractThumbnails:B,downloadFile:v,BIN_DIR:m,downloadYtDlp:_,downloadYtDlpVerified:J,findYtdlpBinary:q};0&&(module.exports={BIN_DIR,YtDlp,helpers});

@@ -1,4 +0,4 @@

import{fileURLToPath as G}from"url";import H from"path";var Z=()=>G(import.meta.url),X=()=>H.dirname(Z()),c=X();import{spawn as A,spawnSync as q}from"child_process";import*as F from"fs";import*as Y from"path";import{Blob as oe}from"buffer";function w(e){let r=[];if(e.printHelp&&r.push("--help"),e.printVersion&&r.push("--version"),e.update&&r.push("--update"),e.noUpdate&&r.push("--no-update"),e.updateTo&&r.push("--update-to",e.updateTo),e.ignoreErrors&&r.push("--ignore-errors"),e.noAbortOnError&&r.push("--no-abort-on-error"),e.abortOnError&&r.push("--abort-on-error"),e.dumpUserAgent&&r.push("--dump-user-agent"),e.listExtractors&&r.push("--list-extractors"),e.extractorDescriptions&&r.push("--extractor-descriptions"),e.useExtractors&&e.useExtractors.length>0&&r.push("--use-extractors",e.useExtractors.join(",")),e.defaultSearch&&r.push("--default-search",e.defaultSearch),e.ignoreConfig&&r.push("--ignore-config"),e.noConfigLocations&&r.push("--no-config-location"),e.configLocations&&e.configLocations.length>0&&r.push("--config-locations",...e.configLocations),e.pluginDirs&&e.pluginDirs.length>0)for(let t of e.pluginDirs)r.push("--plugin-dirs",t);if(e.noPluginDirs&&r.push("--no-plugin-dirs"),e.flatPlaylist&&r.push("--flat-playlist"),e.noFlatPlaylist&&r.push("--no-flat-playlist"),e.liveFromStart&&r.push("--live-from-start"),e.noLiveFromStart&&r.push("--no-live-from-start"),e.waitForVideo&&r.push("--wait-for-video",e.waitForVideo.toString()),e.noWaitForVideo&&r.push("--no-wait-for-video"),e.markWatched&&r.push("--mark-watched"),e.noMarkWatched&&r.push("--no-mark-watched"),e.color&&r.push("--color",e.color),e.compatOptions&&e.compatOptions.length>0&&r.push("--compat-options",e.compatOptions.join(",")),e.aliases&&e.aliases.length>0&&r.push("--alias",...e.aliases),e.proxy&&r.push("--proxy",e.proxy),e.socketTimeout&&r.push("--socket-timeout",e.socketTimeout.toString()),e.sourceAddress&&r.push("--source-address",e.sourceAddress),e.impersonate&&e.impersonate.length>0&&r.push("--impersonate",e.impersonate.join(",")),e.listImpersonateTargets&&r.push("--list-impersonate-targets"),e.forceIpv4&&r.push("--force-ipv4"),e.forceIpv6&&r.push("--force-ipv6"),e.enableFileUrls&&r.push("--enable-file-urls"),e.geoVerificationProxy&&r.push("--geo-verification-proxy",e.geoVerificationProxy),e.xff&&r.push("--xff",e.xff),e.playlistItems&&r.push("--playlist-items",e.playlistItems),e.minFilesize&&r.push("--min-filesize",e.minFilesize),e.maxFilesize&&r.push("--max-filesize",e.maxFilesize),e.date&&r.push("--date",e.date),e.dateBefore&&r.push("--datebefore",e.dateBefore),e.dateAfter&&r.push("--dateafter",e.dateAfter),e.matchFilter&&r.push("--match-filter",e.matchFilter),e.noMatchFilters&&r.push("--no-match-filters"),e.breakMatchFilters&&r.push("--break-match-filters",e.breakMatchFilters),e.noBreakMatchFilters&&r.push("--no-break-match-filters"),e.noPlaylist&&r.push("--no-playlist"),e.yesPlaylist&&r.push("--yes-playlist"),e.ageLimit&&r.push("--age-limit",e.ageLimit.toString()),e.downloadArchive&&r.push("--download-archive",e.downloadArchive),e.noDownloadArchive&&r.push("--no-download-archive"),e.maxDownloads&&r.push("--max-downloads",e.maxDownloads.toString()),e.breakOnExisting&&r.push("--break-on-existing"),e.noBreakOnExisting&&r.push("--no-break-on-existing"),e.breakPerInput&&r.push("--break-per-input"),e.noBreakPerInput&&r.push("--break-per-input"),e.skipPlaylistAfterErrors&&r.push("--skip-playlist-after-errors",e.skipPlaylistAfterErrors.toString()),e.concurrentFragments&&r.push("--concurrent-fragments",e.concurrentFragments.toString()),e.limitRate&&r.push("--limit-rate",e.limitRate),e.throttledRate&&r.push("--throttled-rate",e.throttledRate),e.retries&&r.push("--retries",e.retries.toString()),e.fileAccessRetries&&r.push("--file-access-retries",e.fileAccessRetries.toString()),e.fragmentRetries&&r.push("--fragment-retries",e.fragmentRetries.toString()),e.retrySleep&&r.push("--retry-sleep",e.retrySleep.toString()),e.skipUnavailableFragments&&r.push("--skip-unavailable-fragments"),e.abortOnUnavailableFragment&&r.push("--abort-on-unavailable-fragment"),e.keepFragments&&r.push("--keep-fragments"),e.noKeepFragments&&r.push("--no-keep-fragments"),e.bufferSize&&r.push("--buffer-size",e.bufferSize),e.resizeBuffer&&r.push("--resize-buffer"),e.noResizeBuffer&&r.push("--no-resize-buffer"),e.httpChunkSize&&r.push("--http-chunk-size",e.httpChunkSize),e.playlistRandom&&r.push("--playlist-random"),e.lazyPlaylist&&r.push("--lazy-playlist"),e.noLazyPlaylist&&r.push("--no-lazy-playlist"),e.xattrSetFilesize&&r.push("--xattr-set-filesize"),e.hlsUseMpegts&&r.push("--hls-use-mpegts"),e.noHlsUseMpegts&&r.push("--no-hls-use-mpegts"),e.downloadSections&&r.push("--download-sections",e.downloadSections.toString()),e.downloader&&r.push("--downloader",e.downloader),e.downloaderArgs&&r.push("--downloader-args",e.downloaderArgs),e.batchFile&&r.push("--batch-file",e.batchFile),e.noBatchFile&&r.push("--no-batch-file"),e.paths)if(typeof e.paths=="string")r.push("--paths",e.paths);else for(let[t,s]of Object.entries(e.paths))r.push("--paths",`${t}:${s}`);if(e.output&&r.push("-o",e.output),e.outputNaPlaceholder&&r.push("--output-na-placeholder",e.outputNaPlaceholder),e.restrictFilenames&&r.push("--restrict-filenames"),e.noRestrictFilenames&&r.push("--no-restrict-filenames"),e.windowsFilenames&&r.push("--windows-filenames"),e.noWindowsFilenames&&r.push("--no-windows-filenames"),e.trimFileNames&&r.push("--trim-file-names",e.trimFileNames.toString()),e.noOverwrites&&r.push("--no-overwrites"),e.forceOverwrites&&r.push("--force-overwrites"),e.noForceOverwrites&&r.push("--no-force-overwrites"),e.continue&&r.push("--continue"),e.noContinue&&r.push("--no-continue"),e.part&&r.push("--part"),e.noPart&&r.push("--no-part"),e.mtime&&r.push("--mtime"),e.noMtime&&r.push("--no-mtime"),e.writeDescription&&r.push("--write-description"),e.noWriteDescription&&r.push("--no-write-description"),e.writeInfoJson&&r.push("--write-info-json"),e.noWriteInfoJson&&r.push("--no-write-info-json"),e.writePlaylistMetafiles&&r.push("--write-playlist-metafiles"),e.noWritePlaylistMetafiles&&r.push("--no-write-playlist-metafiles"),e.cleanInfoJson&&r.push("--clean-info-json"),e.noCleanInfoJson&&r.push("--no-clean-info-json"),e.writeComments&&r.push("--write-comments"),e.noWriteComments&&r.push("--no-write-comments"),e.loadInfoJson&&r.push("--load-info-json",e.loadInfoJson.toString()),e.cookies&&r.push("--cookies",e.cookies),e.noCookies&&r.push("--no-cookies"),e.cookiesFromBrowser&&r.push("--cookies-from-browser",e.cookiesFromBrowser),e.noCookiesFromBrowser&&r.push("--no-cookies-from-browser"),e.cacheDir&&r.push("--cache-dir",e.cacheDir),e.noCacheDir&&r.push("--no-cache-dir"),e.rmCacheDir&&r.push("--rm-cache-dir"),e.writeThumbnail&&r.push("--write-thumbnail"),e.noWriteThumbnails&&r.push("--no-write-thumbnails"),e.writeAllThumbnails&&r.push("--write-all-thumbnails"),e.listThumbnails&&r.push("--list-thumbnails"),e.writeLink&&r.push("--write-link"),e.writeUrlLink&&r.push("--write-url-link"),e.writeWeblocLink&&r.push("--write-webloc-link"),e.writeDesktopLink&&r.push("--write-desktop-link"),e.quiet&&r.push("--quiet"),e.noQuiet&&r.push("--no-quiet"),e.noWarnings&&r.push("--no-warnings"),e.simulate&&r.push("--simulate"),e.noSimulate&&r.push("--no-simulate"),e.ignoreNoFormatsError&&r.push("--ignore-no-formats-error"),e.noIgnoreNoFormatsError&&r.push("--no-ignore-no-formats-error"),e.skipDownload&&r.push("--skip-download"),e.print&&r.push("--print",e.print),e.printToFile&&r.push("--print-to-file",e.printToFile),e.dumpJson&&r.push("--dump-json"),e.dumpSingleJson&&r.push("--dump-single-json"),e.forceWriteArchive&&r.push("--force-write-archive"),e.newline&&r.push("--newline"),e.noProgress&&r.push("--no-progress"),e.progress&&r.push("--progress"),e.consoleTitle&&r.push("--console-title"),e.progressTemplate&&r.push("--progress-template",e.progressTemplate),e.progressDelta&&r.push("--progress-delta",e.progressDelta.toString()),e.verbose&&r.push("--verbose"),e.dumpPages&&r.push("--dump-pages"),e.writePages&&r.push("--write-pages"),e.printTraffic&&r.push("--print-traffic"),e.encoding&&r.push("--encoding",e.encoding),e.legacyServerConnect&&r.push("--legacy-server-connect"),e.noCheckCertificates&&r.push("--no-check-certificates"),e.preferInsecure&&r.push("--prefer-insecure"),e.addHeaders)for(let[t,s]of Object.entries(e.addHeaders))r.push("--add-headers",`${t}:${s}`);if(e.bidiWorkaround&&r.push("--bidi-workaround"),e.sleepRequests&&r.push("--sleep-requests",e.sleepRequests.toString()),e.sleepInterval&&r.push("--sleep-interval",e.sleepInterval.toString()),e.maxSleepInterval&&r.push("--max-sleep-interval",e.maxSleepInterval.toString()),e.sleepSubtitles&&r.push("--sleep-subtitles",e.sleepSubtitles.toString()),e.format&&r.push("-f",e.format),e.formatSort&&e.formatSort.length>0&&r.push("--format-sort",e.formatSort.join(",")),e.formatSortForce&&r.push("--format-sort-force"),e.noFormatSortForce&&r.push("--no-format-sort-force"),e.videoMultiStreams&&r.push("--video-multistreams"),e.noVideoMultiStreams&&r.push("--no-video-multistreams"),e.audioMultiStreams&&r.push("--audio-multistreams"),e.noAudioMultiStreams&&r.push("--no-audio-multistreams"),e.preferFreeFormats&&r.push("--prefer-free-formats"),e.noPreferFreeFormats&&r.push("--no-prefer-free-formats"),e.checkFormats&&r.push("--check-formats"),e.checkAllFormats&&r.push("--check-all-formats"),e.noCheckFormats&&r.push("--no-check-formats"),e.listFormats&&r.push("--list-formats"),e.mergeOutputFormat&&r.push("--merge-output-format",e.mergeOutputFormat),e.writeSubs&&r.push("--write-subs"),e.noWriteSubs&&r.push("--no-write-subs"),e.writeAutoSubs&&r.push("--write-auto-subs"),e.writeAllSubs&&r.push("--all-subs"),e.listSubs&&r.push("--list-subs"),e.subFormat&&r.push("--sub-format",e.subFormat),e.subLangs&&e.subLangs.length>0&&r.push("--sub-langs",e.subLangs.join(",")),e.username&&r.push("--username",e.username),e.password&&r.push("--password",e.password),e.twoFactor&&r.push("--twofactor",e.twoFactor),e.netrc&&r.push("--netrc"),e.videoPassword&&r.push("--video-password",e.videoPassword),e.apMso&&r.push("--ap-mso",e.apMso),e.apUsername&&r.push("--ap-username",e.apUsername),e.apPassword&&r.push("--ap-password",e.apPassword),e.netrcLocation&&r.push("--netrc-location",e.netrcLocation),e.netrcCmd&&r.push("--netrc-cmd",e.netrcCmd),e.apListMso&&r.push("--ap-list-mso"),e.clientCertificate&&r.push("--client-certificate",e.clientCertificate),e.clientCertificateKey&&r.push("--client-certificate-key",e.clientCertificateKey),e.clientCertificatePassword&&r.push("--client-certificate-password",e.clientCertificatePassword),e.extractorRetries!==void 0&&r.push("--extractor-retries",e.extractorRetries.toString()),e.allowDynamicMpd&&r.push("--allow-dynamic-mpd"),e.ignoreDynamicMpd&&r.push("--ignore-dynamic-mpd"),e.hlsSplitDiscontinuity&&r.push("--hls-split-discontinuity"),e.noHlsSplitDiscontinuity&&r.push("--no-hls-split-discontinuity"),e.extractorArgs)for(let[t,s]of Object.entries(e.extractorArgs))r.push("--extractor-args",`${t}:${s.join(" ")}`);if(e.playlistStart!==void 0&&r.push("--playlist-start",e.playlistStart.toString()),e.playlistEnd!==void 0&&r.push("--playlist-end",e.playlistEnd.toString()),e.matchTitle&&r.push("--match-title",e.matchTitle),e.rejectTitle&&r.push("--reject-title",e.rejectTitle),e.includeAds&&r.push("--include-ads"),e.breakOnReject&&r.push("--break-on-reject"),e.noDownload&&r.push("--no-download"),e.playlistReverse&&r.push("--playlist-reverse"),e.geoBypass&&r.push("--geo-bypass"),e.geoBypassCountry&&r.push("--geo-bypass-country",e.geoBypassCountry),e.geoBypassIpBlock&&r.push("--geo-bypass-ip-block",e.geoBypassIpBlock),e.convertThumbnails&&r.push("--convert-thumbnails",e.convertThumbnails),e.writeLink&&r.push("--write-link"),e.writeUrlLink&&r.push("--write-url-link"),e.writeWeblocLink&&r.push("--write-webloc-link"),e.writeLnkLink&&r.push("--write-lnk-link"),e.userAgent&&r.push("--user-agent",e.userAgent),e.extractAudio&&r.push("--extract-audio"),e.audioFormat&&r.push("--audio-format",e.audioFormat),e.audioQuality&&r.push("--audio-quality",e.audioQuality),e.remuxVideo&&r.push("--remux-video",e.remuxVideo),e.recodeVideo&&r.push("--recode-video",e.recodeVideo),e.postprocessorArgs)for(let[t,s]of Object.entries(e.postprocessorArgs))r.push("--postprocessor-args",`${t}:${s.join(" ")}`);if(e.keepVideo&&r.push("--keep-video"),e.noKeepVideo&&r.push("--no-keep-video"),e.postOverwrites&&r.push("--post-overwrites"),e.noPostOverwrites&&r.push("--no-post-overwrites"),e.embedSubs&&r.push("--embed-subs"),e.noEmbedSubs&&r.push("--no-embed-subs"),e.embedThumbnail&&r.push("--embed-thumbnail"),e.noEmbedThumbnail&&r.push("--no-embed-thumbnail"),e.embedMetadata&&r.push("--embed-metadata"),e.noEmbedMetadata&&r.push("--no-embed-metadata"),e.embedChapters&&r.push("--embed-chapters"),e.noEmbedChapters&&r.push("--no-embed-chapters"),e.embedInfoJson&&r.push("--embed-info-json"),e.noEmbedInfoJson&&r.push("--no-embed-info-json"),e.parseMetadata)for(let[t,s]of Object.entries(e.parseMetadata))r.push("--parse-metadata",`${t}:${s}`);if(e.replaceInMetadata)for(let[t,[s,i]]of Object.entries(e.replaceInMetadata))r.push("--replace-in-metadata",`${t} ${s} ${i}`);if(e.xattrs&&r.push("--xattrs"),e.concatPlaylist&&r.push("--concat-playlist",e.concatPlaylist),e.fixup&&r.push("--fixup",e.fixup),e.ffmpegLocation&&r.push("--ffmpeg-location",e.ffmpegLocation),e.exec&&r.push("--exec",e.exec),e.noExec&&r.push("--no-exec"),e.convertSubs&&r.push("--convert-subs",e.convertSubs),e.convertThumbnails&&r.push("--convert-thumbnails",e.convertThumbnails),e.splitChapters&&r.push("--split-chapters"),e.noSplitChapters&&r.push("--no-split-chapters"),e.removeChapters&&r.push("--remove-chapters",e.removeChapters),e.noRemoveChapters&&r.push("--no-remove-chapters"),e.forceKeyframesAtCuts&&r.push("--force-keyframes-at-cuts"),e.noForceKeyframesAtCuts&&r.push("--no-force-keyframes-at-cuts"),e.usePostProcessor&&e.usePostProcessor.length>0)for(let t of e.usePostProcessor)r.push("--use-postprocessor",t);return e.sponsorblockMark&&e.sponsorblockMark.length>0&&r.push("--sponsorblock-mark",e.sponsorblockMark.join(",")),e.sponsorblockRemove&&e.sponsorblockRemove.length>0&&r.push("--sponsorblock-remove",e.sponsorblockRemove.join(",")),e.sponsorblockChapterTitle&&r.push("--sponsorblock-chapter-title",e.sponsorblockChapterTitle),e.noSponsorblock&&r.push("--no-sponsorblock"),e.sponsorblockApi&&r.push("--sponsorblock-api",e.sponsorblockApi),e.additionalOptions&&e.additionalOptions.length>0&&r.push(...e.additionalOptions),r}function R(e){let r=[],t=e.split(`
`).slice(1);for(let s of t){let i=s.match(/(\d+)\s+(\S+)\s+(\S+)\s+(https:\/\/[\S]+)/);i&&r.push({id:parseInt(i[1],10),width:i[2]==="unknown"?"unknown":parseInt(i[2],10),height:i[3]==="unknown"?"unknown":parseInt(i[3],10),url:i[4]})}return r}var L={"2160p":"bv*[height<=2160]","1440p":"bv*[height<=1440]","1080p":"bv*[height<=1080]","720p":"bv*[height<=720]","480p":"bv*[height<=480]","360p":"bv*[height<=360]","240p":"bv*[height<=240]","144p":"bv*[height<=133]",highest:"bv*",lowest:"wv*"};function b(e){if(!e)return[];if(typeof e=="string")return["-f",e];if(Object.keys(e).length===0)return["-f","bv*+ba"];let r=[],{filter:t,quality:s,type:i}=e;return t==="audioonly"&&(r=["-x","--audio-format",i||"mp3","--audio-quality",s?s.toString():"5"]),t==="videoonly"&&(r=["-f",(s?L[s]:"bv*")+"[acodec=none]"]),t==="audioandvideo"&&(r=["-f",(s=="lowest"?"w*":"b*")+"[vcodec!=none][acodec!=none][ext="+(i||"mp4")+"]"]),t==="mergevideo"&&(r=["-f",`${s?L[s]:"bv*"}+ba`],i&&r.push("--merge-output-format",i)),r}function k(e){if(!e||typeof e=="string")return"video/mp4";let{filter:r,type:t}=e;switch(r){case"videoonly":case"audioandvideo":switch(t){case"mp4":return"video/mp4";case"webm":return"video/webm";default:return"video/mp4"}case"audioonly":switch(t){case"aac":return"audio/aac";case"flac":return"audio/flac";case"mp3":return"audio/mp3";case"m4a":return"audio/mp4";case"opus":return"audio/opus";case"vorbis":return"audio/vorbis";case"wav":return"audio/wav";case"alac":return"audio/mp4";default:return"audio/mpeg"}case"mergevideo":switch(t){case"webm":return"video/webm";case"mkv":return"video/x-matroska";case"ogg":return"video/ogg";case"flv":return"video/x-flv";default:return"video/mp4"}}}function B(e){if(!e||typeof e=="string")return"mp4";let{filter:r,type:t}=e;return t||(r==="audioonly"?"mp3":"mp4")}var E='bright-{"status":"%(progress.status)s","downloaded":"%(progress.downloaded_bytes)s","total":"%(progress.total_bytes)s","total_estimate":"%(progress.total_bytes_estimate)s","speed":"%(progress.speed)s","eta":"%(progress.eta)s"}';function D(e,r=2){let t=Number(e);if(t===0||isNaN(t))return t+" Bytes";let s=1024,i=r<0?0:r,n=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],a=Math.floor(Math.log(t)/Math.log(s));return parseFloat((t/Math.pow(s,a)).toFixed(i))+" "+n[a]}function ee(e,r,t){let s=Math.pow(t||10,r);return Math.round(e*s)/s}function W(e,r){return ee(100*Number(e)/Number(r),2)}function re(e){e=Number(e);let r=Math.floor(e/3600),t=Math.floor(e%3600/60),s=Math.floor(e%3600%60),i=r>0?r+(r==1?" hour, ":" hours, "):"",n=t>0?t+(t==1?" minute, ":" minutes, "):"",a=s>=0?s+(s==1?" second":" seconds"):"";return i+n+a}function m(e){try{if(!e.includes("bright"))throw new Error;let r=e.split("\r")?.[1]?.trim()?.split("-")?.[1];if(!r)throw new Error;let t=JSON.parse(r),s=isNaN(Number(t.total))?Number(t.total_estimate):Number(t.total);return{status:t.status,downloaded:Number(t.downloaded),downloaded_str:D(t.downloaded),total:s,total_str:D(s),speed:Number(t.speed),speed_str:D(t.speed)+"/s",eta:Number(t.eta),eta_str:re(t.eta),percentage:W(t.downloaded,s),percentage_str:W(t.downloaded,s)+"%"}}catch{return}}import{PassThrough as J}from"stream";import M from"path";import P from"fs";import*as te from"https";import*as se from"http";import{URL as V}from"url";import*as h from"fs";function z(e,r={}){return new Promise((t,s)=>{let a=(new V(e).protocol==="https:"?te:se).get(e,r,o=>{if(o.statusCode>=300&&o.statusCode<400&&o.headers.location){let u=new V(o.headers.location,e).toString();z(u,r).then(t).catch(s);return}t(o)});a.on("error",s),a.setTimeout(3e4,()=>{a.destroy(),s(new Error("Request timed out"))})})}async function y(e,r){try{let t=h.createWriteStream(r),s=await z(e);if(s.statusCode!==200)throw t.close(),h.unlinkSync(r),new Error(`Failed to download file: ${s.statusCode} ${s.statusMessage}`);let i=parseInt(s.headers["content-length"]||"0",10),n=0;return s.on("data",a=>{n+=a.length;let o=n/i*100;process.stdout.write(`Progress: ${Math.round(o)}%\r`)}),s.pipe(t),new Promise((a,o)=>{t.on("finish",()=>{t.close(),console.log(`
Download complete!`),a()}),t.on("error",u=>{t.close(),h.unlinkSync(r),o(u)}),s.on("error",u=>{t.close(),h.unlinkSync(r),o(u)})})}catch(t){throw h.existsSync(r)&&h.unlinkSync(r),t}}var ie="https://github.com/iqbal-rashed/ytdlp-nodejs/releases/download/ffmpeg-latest",_={win32:{x64:["win-x64-ffmpeg.exe","win-x64-ffprobe.exe"],ia32:["win-ia32-ffmpeg.exe","win-ia32-ffprobe.exe"],arm64:["win-arm64-ffmpeg.exe","win-arm64-ffprobe.exe"]},linux:{x64:["linux-x64-ffmpeg","linux-x64-ffprobe"],arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]},darwin:{x64:["macos-x64-ffmpeg","macos-x64-ffprobe"],arm64:["macos-arm64-ffmpeg","macos-arm64-ffprobe"]},android:{arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]}};function U(){let e=process.platform,r=process.arch;if(!_[e]||!_[e][r])throw new Error(`No FFmpeg build available for platform: ${e}, architecture: ${r}`);return _[e][r]}async function C(e){let r=e||g,t=x();if(t)return t;try{let s=U();if(!s.length)throw new Error;let i=s.map(a=>`${ie}/${a}`),n=s.map(a=>M.join(r,String(a.split("-").pop())));P.existsSync(r)||P.mkdirSync(r,{recursive:!0}),console.log("Downloading FFmpeg and FFprobe...");for(let a=0;a<s.length;a++){let o=i[a],u=n[a];console.log("Downloading...",M.basename(o)),await y(o,u)}try{for(let a of n)P.chmodSync(a,493)}catch{console.log("Note: Could not set executable permissions (likely Windows)")}return x()}catch(s){throw console.error(`Download failed: ${s}`),s}}function x(){try{let e=U();if(!e.length)throw new Error;let r=M.join(g,String(e[0].split("-").pop()));if(!P.existsSync(r))throw new Error("FFmpeg binary not found. Please download it first.");return r}catch{return}}import*as d from"fs";import*as N from"path";var ae="https://github.com/yt-dlp/yt-dlp/releases/latest/download",S={win32:{x64:"yt-dlp.exe",ia32:"yt-dlp_x86.exe"},linux:{x64:"yt-dlp",armv7l:"yt-dlp_linux_armv7l",aarch64:"yt-dlp_linux_aarch64",arm64:"yt-dlp"},darwin:{x64:"yt-dlp_macos",arm64:"yt-dlp_macos"},android:{arm64:"yt-dlp"}};function ne(){let e=process.platform,r=process.arch;if(!S[e]||!S[e][r])throw new Error(`No FFmpeg build available for ${e} ${r}`);return S[e][r]}async function K(e){let r=e||g,t=ne(),s=`${ae}/${t}`,i=N.join(r,t);if(d.existsSync(i))return i;console.log("Downloading yt-dlp...",s),d.existsSync(r)||d.mkdirSync(r,{recursive:!0});try{await y(s,i),console.log(`yt-dlp downloaded successfully to: ${i}`);try{d.chmodSync(i,493)}catch{console.log("Error while chmod")}return i}catch(a){throw console.error(`Download failed: ${a}`),a}}function $(){let e=process.platform,r=process.arch;try{let t=S[e][r],s=N.join(g,t);if(!d.existsSync(s))throw new Error("Ytdlp binary not found. Please download it first.");return s}catch{return}}var g=Y.join(c,"..","bin"),Q=class{constructor(r){if(this.binaryPath=r?.binaryPath||$()||"",this.ffmpegPath=r?.ffmpegPath||x(),(!this.binaryPath||!F.existsSync(this.binaryPath))&&console.error(new Error("yt-dlp binary not found. Please install yt-dlp or specify correct binaryPath in options.")),this.ffmpegPath&&!F.existsSync(this.ffmpegPath)&&console.error(new Error(`FFmpeg binary not found at: ${this.ffmpegPath}. Please install FFmpeg or specify correct ffmpegPath.`)),process.platform!=="win32")try{F.chmodSync(this.binaryPath,493)}catch(t){console.error(new Error(`Failed to set executable permissions: ${t instanceof Error?t.message:"Unknown error"}`))}}async checkInstallationAsync(r){return new Promise((t,s)=>{if(r?.ffmpeg&&!this.ffmpegPath)return s(new Error("FFmpeg path is not set"));let i=A(this.binaryPath,["--version"]),n=!1,a=!r?.ffmpeg;i.on("error",()=>n=!1),i.on("exit",o=>{if(n=o===0,r?.ffmpeg){let u=A(this.ffmpegPath,["-version"]);u.on("error",()=>a=!1),u.on("exit",f=>{a=f===0,t(!!(n&&a))})}else t(!!n)})})}checkInstallation(r){if(r?.ffmpeg&&!this.ffmpegPath)throw new Error("FFmpeg path is not set");let t=q(this.binaryPath,["--version"],{stdio:"ignore"}),s=r?.ffmpeg?q(this.ffmpegPath,["-version"],{stdio:"ignore"}):{status:0};return t.status===0&&s.status===0}async execAsync(r,t){let s=this.buildArgs(r,t||{}),i=n=>{if(t?.onData?.(n),t?.onProgress){let a=m(n);a&&t.onProgress?.(a)}};return this._executeAsync(s,i)}exec(r,t){let s=this.buildArgs(r,t||{},!0);return this._execute(s)}_execute(r){let t=A(this.binaryPath,r);return t.stderr.on("data",s=>{let i=Buffer.from(s).toString(),n=m(i);n&&t.emit("progress",n)}),t.stdout.on("data",s=>{let i=Buffer.from(s).toString(),n=m(i);n&&t.emit("progress",n)}),t}async _executeAsync(r,t,s){return new Promise((i,n)=>{this.binaryPath||n(new Error("Ytdlp binary not found"));let a=A(this.binaryPath,r),o="",u="";a.stdout.on("data",f=>{s||(o+=f.toString(),t?.(Buffer.from(f).toString()))}),a.stderr.on("data",f=>{u+=f.toString(),t?.(Buffer.from(f).toString())}),s&&a.stdout.pipe(s),a.on("close",f=>{f===0?i(o):n(new Error(`yt-dlp exited with code ${f}: ${u}`))}),a.on("error",f=>{n(new Error(`Failed to start yt-dlp process: ${f.message}`))})})}buildArgs(r,t,s,i){let n=w(t);return this.ffmpegPath&&n.push("--ffmpeg-location",this.ffmpegPath),s&&n.push("--progress-template",E),i&&n.push(...i),n.concat(r)}download(r,t){let{format:s,...i}=t||{},n=this.buildArgs(r,i,!0,b(s));return this._execute(n)}async downloadAsync(r,t){let{format:s,onProgress:i,...n}=t||{},a=this.buildArgs(r,n,!!i,b(s));return this._executeAsync(a,o=>{let u=m(o);u&&i?.(u)})}stream(r,t){let{format:s,onProgress:i,...n}=t||{},a=this.buildArgs(r,n,!!i,[...b(s),"-o","-"]),o=new J;return{promise:this._executeAsync(a,f=>{let l=m(f);l&&i?.(l)},o),pipe:(f,l)=>o.pipe(f,l),pipeAsync:(f,l)=>new Promise((O,T)=>{let v=o.pipe(f,l);f.on("finish",()=>O(v)),f.on("error",T)})}}async getInfoAsync(r,t){let s=["--dump-single-json","--quiet",...w({flatPlaylist:!0,...t}),r],i=await this._executeAsync(s);return JSON.parse(i)}async getThumbnailsAsync(r){let t=["--print","thumbnails_table","--print","playlist:thumbnails_table","--quiet",r],s=await this._executeAsync(t);return R(s)}async getTitleAsync(r){let t=["--print","title",r];return await this._executeAsync(t)}async downloadFFmpeg(){return C()}async getFileAsync(r,t){let s=await this.getInfoAsync(r),{format:i,filename:n,metadata:a,onProgress:o,...u}=t||{},f=new J,l=[];f.on("data",I=>l.push(Buffer.from(I)));let O=this.buildArgs(r,u,!!o,[...b(i),"-o","-"]);await this._executeAsync(O,I=>{if(o){let j=m(I);j&&o(j)}},f);let T=new oe(l,{type:k(i)}),v={name:n||`${s.title}.${B(i)}`,type:k(i),size:T.size,...a};return new File([Buffer.concat(l)],v.name,{type:v.type})}async getUrlsAsync(r,t){let s=["--print","urls",...w({flatPlaylist:!0,...t}),r],i=await this._executeAsync(s);return String(i).split(`
`)}},Ve={downloadFFmpeg:C,findFFmpegBinary:x,PROGRESS_STRING:E,getContentType:k,getFileExtension:B,parseFormatOptions:b,stringToProgress:m,createArgs:w,extractThumbnails:R,downloadFile:y,BIN_DIR:g,downloadYtDlp:K,findYtdlpBinary:$};export{g as BIN_DIR,Q as YtDlp,Ve as helpers};
import{fileURLToPath as Ce}from"url";import Te from"path";var De=()=>Ce(import.meta.url),Ie=()=>Te.dirname(De()),l=Ie();import{spawn as ve,spawnSync as Se}from"child_process";import*as T from"fs";import He from"path";function h(e){let t=[];if(e.printHelp&&t.push("--help"),e.printVersion&&t.push("--version"),e.update&&t.push("--update"),e.noUpdate&&t.push("--no-update"),e.updateTo&&t.push("--update-to",e.updateTo),e.ignoreErrors&&t.push("--ignore-errors"),e.noAbortOnError&&t.push("--no-abort-on-error"),e.abortOnError&&t.push("--abort-on-error"),e.dumpUserAgent&&t.push("--dump-user-agent"),e.listExtractors&&t.push("--list-extractors"),e.extractorDescriptions&&t.push("--extractor-descriptions"),e.useExtractors&&e.useExtractors.length>0&&t.push("--use-extractors",e.useExtractors.join(",")),e.defaultSearch&&t.push("--default-search",e.defaultSearch),e.ignoreConfig&&t.push("--ignore-config"),e.noConfigLocations&&t.push("--no-config-location"),e.configLocations&&e.configLocations.length>0&&t.push("--config-locations",...e.configLocations),e.pluginDirs&&e.pluginDirs.length>0)for(let s of e.pluginDirs)t.push("--plugin-dirs",s);e.noPluginDirs&&t.push("--no-plugin-dirs"),e.flatPlaylist&&t.push("--flat-playlist"),e.noFlatPlaylist&&t.push("--no-flat-playlist"),e.liveFromStart&&t.push("--live-from-start"),e.noLiveFromStart&&t.push("--no-live-from-start"),e.waitForVideo&&t.push("--wait-for-video",e.waitForVideo.toString()),e.noWaitForVideo&&t.push("--no-wait-for-video"),e.markWatched&&t.push("--mark-watched"),e.noMarkWatched&&t.push("--no-mark-watched"),e.color&&t.push("--color",e.color),e.compatOptions&&e.compatOptions.length>0&&t.push("--compat-options",e.compatOptions.join(",")),e.aliases&&e.aliases.length>0&&t.push("--alias",...e.aliases);let r=e.jsRuntime??"node";if(r&&t.push("--js-runtime",r),e.proxy&&t.push("--proxy",e.proxy),e.socketTimeout&&t.push("--socket-timeout",e.socketTimeout.toString()),e.sourceAddress&&t.push("--source-address",e.sourceAddress),e.impersonate&&e.impersonate.length>0&&t.push("--impersonate",e.impersonate.join(",")),e.listImpersonateTargets&&t.push("--list-impersonate-targets"),e.forceIpv4&&t.push("--force-ipv4"),e.forceIpv6&&t.push("--force-ipv6"),e.enableFileUrls&&t.push("--enable-file-urls"),e.geoVerificationProxy&&t.push("--geo-verification-proxy",e.geoVerificationProxy),e.xff&&t.push("--xff",e.xff),e.playlistItems&&t.push("--playlist-items",e.playlistItems),e.minFilesize&&t.push("--min-filesize",e.minFilesize),e.maxFilesize&&t.push("--max-filesize",e.maxFilesize),e.date&&t.push("--date",e.date),e.dateBefore&&t.push("--datebefore",e.dateBefore),e.dateAfter&&t.push("--dateafter",e.dateAfter),e.matchFilter&&t.push("--match-filter",e.matchFilter),e.noMatchFilters&&t.push("--no-match-filters"),e.breakMatchFilters&&t.push("--break-match-filters",e.breakMatchFilters),e.noBreakMatchFilters&&t.push("--no-break-match-filters"),e.noPlaylist&&t.push("--no-playlist"),e.yesPlaylist&&t.push("--yes-playlist"),e.ageLimit&&t.push("--age-limit",e.ageLimit.toString()),e.downloadArchive&&t.push("--download-archive",e.downloadArchive),e.noDownloadArchive&&t.push("--no-download-archive"),e.maxDownloads&&t.push("--max-downloads",e.maxDownloads.toString()),e.breakOnExisting&&t.push("--break-on-existing"),e.noBreakOnExisting&&t.push("--no-break-on-existing"),e.breakPerInput&&t.push("--break-per-input"),e.noBreakPerInput&&t.push("--break-per-input"),e.skipPlaylistAfterErrors&&t.push("--skip-playlist-after-errors",e.skipPlaylistAfterErrors.toString()),e.concurrentFragments&&t.push("--concurrent-fragments",e.concurrentFragments.toString()),e.limitRate&&t.push("--limit-rate",e.limitRate),e.throttledRate&&t.push("--throttled-rate",e.throttledRate),e.retries&&t.push("--retries",e.retries.toString()),e.fileAccessRetries&&t.push("--file-access-retries",e.fileAccessRetries.toString()),e.fragmentRetries&&t.push("--fragment-retries",e.fragmentRetries.toString()),e.retrySleep&&t.push("--retry-sleep",e.retrySleep.toString()),e.retrySleepByType)for(let[s,i]of Object.entries(e.retrySleepByType))t.push("--retry-sleep",`${s}:${i}`);if(e.skipUnavailableFragments&&t.push("--skip-unavailable-fragments"),e.abortOnUnavailableFragment&&t.push("--abort-on-unavailable-fragment"),e.keepFragments&&t.push("--keep-fragments"),e.noKeepFragments&&t.push("--no-keep-fragments"),e.bufferSize&&t.push("--buffer-size",e.bufferSize),e.resizeBuffer&&t.push("--resize-buffer"),e.noResizeBuffer&&t.push("--no-resize-buffer"),e.httpChunkSize&&t.push("--http-chunk-size",e.httpChunkSize),e.playlistRandom&&t.push("--playlist-random"),e.lazyPlaylist&&t.push("--lazy-playlist"),e.noLazyPlaylist&&t.push("--no-lazy-playlist"),e.xattrSetFilesize&&t.push("--xattr-set-filesize"),e.hlsUseMpegts&&t.push("--hls-use-mpegts"),e.noHlsUseMpegts&&t.push("--no-hls-use-mpegts"),e.downloadSections&&t.push("--download-sections",e.downloadSections.toString()),e.downloader&&t.push("--downloader",e.downloader),e.downloaderArgs&&t.push("--downloader-args",e.downloaderArgs),e.batchFile&&t.push("--batch-file",e.batchFile),e.noBatchFile&&t.push("--no-batch-file"),e.paths)if(typeof e.paths=="string")t.push("--paths",e.paths);else for(let[s,i]of Object.entries(e.paths))t.push("--paths",`${s}:${i}`);if(e.output&&t.push("-o",e.output),e.outputNaPlaceholder&&t.push("--output-na-placeholder",e.outputNaPlaceholder),e.restrictFilenames&&t.push("--restrict-filenames"),e.noRestrictFilenames&&t.push("--no-restrict-filenames"),e.windowsFilenames&&t.push("--windows-filenames"),e.noWindowsFilenames&&t.push("--no-windows-filenames"),e.trimFileNames&&t.push("--trim-file-names",e.trimFileNames.toString()),e.noOverwrites&&t.push("--no-overwrites"),e.forceOverwrites&&t.push("--force-overwrites"),e.noForceOverwrites&&t.push("--no-force-overwrites"),e.continue&&t.push("--continue"),e.noContinue&&t.push("--no-continue"),e.part&&t.push("--part"),e.noPart&&t.push("--no-part"),e.mtime&&t.push("--mtime"),e.noMtime&&t.push("--no-mtime"),e.writeDescription&&t.push("--write-description"),e.noWriteDescription&&t.push("--no-write-description"),e.writeInfoJson&&t.push("--write-info-json"),e.noWriteInfoJson&&t.push("--no-write-info-json"),e.writePlaylistMetafiles&&t.push("--write-playlist-metafiles"),e.noWritePlaylistMetafiles&&t.push("--no-write-playlist-metafiles"),e.cleanInfoJson&&t.push("--clean-info-json"),e.noCleanInfoJson&&t.push("--no-clean-info-json"),e.writeComments&&t.push("--write-comments"),e.noWriteComments&&t.push("--no-write-comments"),e.loadInfoJson&&t.push("--load-info-json",e.loadInfoJson.toString()),e.cookies&&t.push("--cookies",e.cookies),e.noCookies&&t.push("--no-cookies"),e.cookiesFromBrowser&&t.push("--cookies-from-browser",e.cookiesFromBrowser),e.noCookiesFromBrowser&&t.push("--no-cookies-from-browser"),e.cacheDir&&t.push("--cache-dir",e.cacheDir),e.noCacheDir&&t.push("--no-cache-dir"),e.rmCacheDir&&t.push("--rm-cache-dir"),e.writeThumbnail&&t.push("--write-thumbnail"),e.noWriteThumbnails&&t.push("--no-write-thumbnails"),e.writeAllThumbnails&&t.push("--write-all-thumbnails"),e.listThumbnails&&t.push("--list-thumbnails"),e.writeLink&&t.push("--write-link"),e.writeUrlLink&&t.push("--write-url-link"),e.writeWeblocLink&&t.push("--write-webloc-link"),e.writeDesktopLink&&t.push("--write-desktop-link"),e.quiet&&t.push("--quiet"),e.noQuiet&&t.push("--no-quiet"),e.noWarnings&&t.push("--no-warnings"),e.simulate&&t.push("--simulate"),e.noSimulate&&t.push("--no-simulate"),e.ignoreNoFormatsError&&t.push("--ignore-no-formats-error"),e.noIgnoreNoFormatsError&&t.push("--no-ignore-no-formats-error"),e.skipDownload&&t.push("--skip-download"),e.print&&t.push("--print",e.print),e.printToFile&&t.push("--print-to-file",e.printToFile),e.dumpJson&&t.push("--dump-json"),e.dumpSingleJson&&t.push("--dump-single-json"),e.forceWriteArchive&&t.push("--force-write-archive"),e.newline&&t.push("--newline"),e.noProgress&&t.push("--no-progress"),e.progress&&t.push("--progress"),e.consoleTitle&&t.push("--console-title"),e.progressTemplate&&t.push("--progress-template",e.progressTemplate),e.progressDelta&&t.push("--progress-delta",e.progressDelta.toString()),e.verbose&&t.push("--verbose"),e.dumpPages&&t.push("--dump-pages"),e.writePages&&t.push("--write-pages"),e.printTraffic&&t.push("--print-traffic"),e.encoding&&t.push("--encoding",e.encoding),e.legacyServerConnect&&t.push("--legacy-server-connect"),e.noCheckCertificates&&t.push("--no-check-certificates"),e.preferInsecure&&t.push("--prefer-insecure"),e.addHeaders)for(let[s,i]of Object.entries(e.addHeaders))t.push("--add-header",`${s}:${i}`);if(e.headers)for(let[s,i]of Object.entries(e.headers))t.push("--add-header",`${s}:${i}`);if(e.bidiWorkaround&&t.push("--bidi-workaround"),e.sleepRequests&&t.push("--sleep-requests",e.sleepRequests.toString()),e.sleepInterval&&t.push("--sleep-interval",e.sleepInterval.toString()),e.maxSleepInterval&&t.push("--max-sleep-interval",e.maxSleepInterval.toString()),e.sleepSubtitles&&t.push("--sleep-subtitles",e.sleepSubtitles.toString()),e.format&&t.push("-f",e.format),e.formatSort&&e.formatSort.length>0&&t.push("--format-sort",e.formatSort.join(",")),e.formatSortForce&&t.push("--format-sort-force"),e.noFormatSortForce&&t.push("--no-format-sort-force"),e.videoMultiStreams&&t.push("--video-multistreams"),e.noVideoMultiStreams&&t.push("--no-video-multistreams"),e.audioMultiStreams&&t.push("--audio-multistreams"),e.noAudioMultiStreams&&t.push("--no-audio-multistreams"),e.preferFreeFormats&&t.push("--prefer-free-formats"),e.noPreferFreeFormats&&t.push("--no-prefer-free-formats"),e.checkFormats&&t.push("--check-formats"),e.checkAllFormats&&t.push("--check-all-formats"),e.noCheckFormats&&t.push("--no-check-formats"),e.listFormats&&t.push("--list-formats"),e.mergeOutputFormat&&t.push("--merge-output-format",e.mergeOutputFormat),e.writeSubs&&t.push("--write-subs"),e.noWriteSubs&&t.push("--no-write-subs"),e.writeAutoSubs&&t.push("--write-auto-subs"),e.writeAllSubs&&t.push("--all-subs"),e.listSubs&&t.push("--list-subs"),e.subFormat&&t.push("--sub-format",e.subFormat),e.subLangs&&e.subLangs.length>0&&t.push("--sub-langs",e.subLangs.join(",")),e.username&&t.push("--username",e.username),e.password&&t.push("--password",e.password),e.twoFactor&&t.push("--twofactor",e.twoFactor),e.netrc&&t.push("--netrc"),e.videoPassword&&t.push("--video-password",e.videoPassword),e.apMso&&t.push("--ap-mso",e.apMso),e.apUsername&&t.push("--ap-username",e.apUsername),e.apPassword&&t.push("--ap-password",e.apPassword),e.netrcLocation&&t.push("--netrc-location",e.netrcLocation),e.netrcCmd&&t.push("--netrc-cmd",e.netrcCmd),e.apListMso&&t.push("--ap-list-mso"),e.clientCertificate&&t.push("--client-certificate",e.clientCertificate),e.clientCertificateKey&&t.push("--client-certificate-key",e.clientCertificateKey),e.clientCertificatePassword&&t.push("--client-certificate-password",e.clientCertificatePassword),e.extractorRetries!==void 0&&t.push("--extractor-retries",e.extractorRetries.toString()),e.allowDynamicMpd&&t.push("--allow-dynamic-mpd"),e.ignoreDynamicMpd&&t.push("--ignore-dynamic-mpd"),e.hlsSplitDiscontinuity&&t.push("--hls-split-discontinuity"),e.noHlsSplitDiscontinuity&&t.push("--no-hls-split-discontinuity"),e.extractorArgs)for(let[s,i]of Object.entries(e.extractorArgs))t.push("--extractor-args",`${s}:${i.join(" ")}`);if(e.playlistStart!==void 0&&t.push("--playlist-start",e.playlistStart.toString()),e.playlistEnd!==void 0&&t.push("--playlist-end",e.playlistEnd.toString()),e.matchTitle&&t.push("--match-title",e.matchTitle),e.rejectTitle&&t.push("--reject-title",e.rejectTitle),e.includeAds&&t.push("--include-ads"),e.breakOnReject&&t.push("--break-on-reject"),e.noDownload&&t.push("--no-download"),e.playlistReverse&&t.push("--playlist-reverse"),e.geoBypass&&t.push("--geo-bypass"),e.geoBypassCountry&&t.push("--geo-bypass-country",e.geoBypassCountry),e.geoBypassIpBlock&&t.push("--geo-bypass-ip-block",e.geoBypassIpBlock),e.convertThumbnails&&t.push("--convert-thumbnails",e.convertThumbnails),e.writeLink&&t.push("--write-link"),e.writeUrlLink&&t.push("--write-url-link"),e.writeWeblocLink&&t.push("--write-webloc-link"),e.writeLnkLink&&t.push("--write-lnk-link"),e.referer&&t.push("--referer",e.referer),e.userAgent&&t.push("--user-agent",e.userAgent),e.extractAudio&&t.push("--extract-audio"),e.audioFormat&&t.push("--audio-format",e.audioFormat),e.audioQuality&&t.push("--audio-quality",e.audioQuality),e.remuxVideo&&t.push("--remux-video",e.remuxVideo),e.recodeVideo&&t.push("--recode-video",e.recodeVideo),e.postprocessorArgs)for(let[s,i]of Object.entries(e.postprocessorArgs))t.push("--postprocessor-args",`${s}:${i.join(" ")}`);if(e.keepVideo&&t.push("--keep-video"),e.noKeepVideo&&t.push("--no-keep-video"),e.postOverwrites&&t.push("--post-overwrites"),e.noPostOverwrites&&t.push("--no-post-overwrites"),e.embedSubs&&t.push("--embed-subs"),e.noEmbedSubs&&t.push("--no-embed-subs"),e.embedThumbnail&&t.push("--embed-thumbnail"),e.noEmbedThumbnail&&t.push("--no-embed-thumbnail"),e.embedMetadata&&t.push("--embed-metadata"),e.noEmbedMetadata&&t.push("--no-embed-metadata"),e.embedChapters&&t.push("--embed-chapters"),e.noEmbedChapters&&t.push("--no-embed-chapters"),e.embedInfoJson&&t.push("--embed-info-json"),e.noEmbedInfoJson&&t.push("--no-embed-info-json"),e.parseMetadata)for(let[s,i]of Object.entries(e.parseMetadata))t.push("--parse-metadata",`${s}:${i}`);if(e.replaceInMetadata)for(let[s,[i,n]]of Object.entries(e.replaceInMetadata))t.push("--replace-in-metadata",`${s} ${i} ${n}`);if(e.xattrs&&t.push("--xattrs"),e.concatPlaylist&&t.push("--concat-playlist",e.concatPlaylist),e.fixup&&t.push("--fixup",e.fixup),e.ffmpegLocation&&t.push("--ffmpeg-location",e.ffmpegLocation),e.exec&&t.push("--exec",e.exec),e.noExec&&t.push("--no-exec"),e.convertSubs&&t.push("--convert-subs",e.convertSubs),e.convertThumbnails&&t.push("--convert-thumbnails",e.convertThumbnails),e.splitChapters&&t.push("--split-chapters"),e.noSplitChapters&&t.push("--no-split-chapters"),e.removeChapters&&t.push("--remove-chapters",e.removeChapters),e.noRemoveChapters&&t.push("--no-remove-chapters"),e.forceKeyframesAtCuts&&t.push("--force-keyframes-at-cuts"),e.noForceKeyframesAtCuts&&t.push("--no-force-keyframes-at-cuts"),e.usePostProcessor&&e.usePostProcessor.length>0)for(let s of e.usePostProcessor)t.push("--use-postprocessor",s);return e.sponsorblockMark&&e.sponsorblockMark.length>0&&t.push("--sponsorblock-mark",e.sponsorblockMark.join(",")),e.sponsorblockRemove&&e.sponsorblockRemove.length>0&&t.push("--sponsorblock-remove",e.sponsorblockRemove.join(",")),e.sponsorblockChapterTitle&&t.push("--sponsorblock-chapter-title",e.sponsorblockChapterTitle),e.noSponsorblock&&t.push("--no-sponsorblock"),e.sponsorblockApi&&t.push("--sponsorblock-api",e.sponsorblockApi),e.additionalOptions&&e.additionalOptions.length>0&&t.push(...e.additionalOptions),e.rawArgs&&e.rawArgs.length>0&&t.push(...e.rawArgs),t}function I(e){let t=[],r=e.split(`
`).slice(1);for(let s of r){let i=s.match(/(\d+)\s+(\S+)\s+(\S+)\s+(https:\/\/[\S]+)/);i&&t.push({id:parseInt(i[1],10),width:i[2]==="unknown"?"unknown":parseInt(i[2],10),height:i[3]==="unknown"?"unknown":parseInt(i[3],10),url:i[4]})}return t}var H={"2160p":"bv*[height<=2160]","1440p":"bv*[height<=1440]","1080p":"bv*[height<=1080]","720p":"bv*[height<=720]","480p":"bv*[height<=480]","360p":"bv*[height<=360]","240p":"bv*[height<=240]","144p":"bv*[height<=133]",highest:"bv*",lowest:"wv*"};function x(e){if(!e)return[];if(typeof e=="string")return["-f",e];if(Object.keys(e).length===0)return["-f","bv*+ba"];let t=[],{filter:r,quality:s,type:i}=e;return r==="audioonly"&&(t=["-x","--audio-format",i||"mp3","--audio-quality",s?s.toString():"5"]),r==="videoonly"&&(t=["-f",(s?H[s]:"bv*")+"[acodec=none]"]),r==="audioandvideo"&&(t=["-f",(s=="lowest"?"w*":"b*")+"[vcodec!=none][acodec!=none][ext="+(i||"mp4")+"]"]),r==="mergevideo"&&(t=["-f",`${s?H[s]:"bv*"}+ba`],i&&t.push("--merge-output-format",i)),t}function R(e){if(!e||typeof e=="string")return"video/mp4";let{filter:t,type:r}=e;switch(t){case"videoonly":case"audioandvideo":switch(r){case"mp4":return"video/mp4";case"webm":return"video/webm";default:return"video/mp4"}case"audioonly":switch(r){case"aac":return"audio/aac";case"flac":return"audio/flac";case"mp3":return"audio/mp3";case"m4a":return"audio/mp4";case"opus":return"audio/opus";case"vorbis":return"audio/vorbis";case"wav":return"audio/wav";case"alac":return"audio/mp4";default:return"audio/mpeg"}case"mergevideo":switch(r){case"webm":return"video/webm";case"mkv":return"video/x-matroska";case"ogg":return"video/ogg";case"flv":return"video/x-flv";default:return"video/mp4"}}}function Q(e){if(!e||typeof e=="string")return"mp4";let{filter:t,type:r}=e;return r||(t==="audioonly"?"mp3":"mp4")}function X(e){if(!e?.extractAudio)return null;switch(e.audioFormat||"mp3"){case"aac":return"audio/aac";case"flac":return"audio/flac";case"mp3":return"audio/mpeg";case"m4a":return"audio/mp4";case"opus":return"audio/opus";case"vorbis":return"audio/vorbis";case"wav":return"audio/wav";case"alac":return"audio/mp4";default:return"audio/mpeg"}}var E="~ytdlp-progress-%(progress)#j";function _(e,t=2){let r=Number(e);if(r===0||isNaN(r))return r+" Bytes";let s=1024,i=t<0?0:t,n=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],a=Math.floor(Math.log(r)/Math.log(s));return parseFloat((r/Math.pow(s,a)).toFixed(i))+" "+n[a]}function Re(e,t,r){let s=Math.pow(r||10,t);return Math.round(e*s)/s}function Ee(e){e=Number(e);let t=Math.floor(e/3600),r=Math.floor(e%3600/60),s=Math.floor(e%3600%60),i=t>0?t+(t==1?" hour, ":" hours, "):"",n=r>0?r+(r==1?" minute, ":" minutes, "):"",a=s>=0?s+(s==1?" second":" seconds"):"";return i+n+a}function g(e){try{if(!e.includes("~ytdlp-progress-"))throw new Error;let t=e.trim().replace("~ytdlp-progress-","");if(!t)throw new Error;let r=JSON.parse(t),s=f=>{if(f==null||f==="NA")return;let d=Number(f);return isNaN(d)?void 0:d},i=s(r.downloaded_bytes),n=s(r.total_bytes)??s(r.total_bytes_estimate),a=s(r.speed),o=s(r.eta),u=i!==void 0&&n!==void 0&&n>0?Re(100*i/n,2):void 0;return{filename:r.filename,status:r.status,downloaded:i,downloaded_str:i!==void 0?_(i):void 0,total:n,total_str:n!==void 0?_(n):void 0,speed:a,speed_str:a!==void 0?_(a)+"/s":void 0,eta:o,eta_str:o!==void 0?Ee(o):void 0,percentage:u,percentage_str:u!==void 0?u+"%":void 0}}catch{return}}import W from"path";import B from"fs";import*as Be from"https";import*as je from"http";import{URL as Z}from"url";import*as y from"fs";function N(e,t={}){return new Promise((r,s)=>{let a=(new Z(e).protocol==="https:"?Be:je).get(e,t,o=>{if(o.statusCode>=300&&o.statusCode<400&&o.headers.location){let u=new Z(o.headers.location,e).toString();N(u,t).then(r).catch(s);return}r(o)});a.on("error",s),a.setTimeout(3e4,()=>{a.destroy(),s(new Error("Request timed out"))})})}async function v(e,t){try{let r=y.createWriteStream(t),s=await N(e);if(s.statusCode!==200)throw r.close(),y.unlinkSync(t),new Error(`Failed to download file: ${s.statusCode} ${s.statusMessage}`);let i=parseInt(s.headers["content-length"]||"0",10),n=0;return s.on("data",a=>{n+=a.length;let o=n/i*100;process.stdout.write(`Progress: ${Math.round(o)}%\r`)}),s.pipe(r),new Promise((a,o)=>{r.on("finish",()=>{r.close(),console.log(`
Download complete!`),a()}),r.on("error",u=>{r.close(),y.unlinkSync(t),o(u)}),s.on("error",u=>{r.close(),y.unlinkSync(t),o(u)})})}catch(r){throw y.existsSync(t)&&y.unlinkSync(t),r}}async function ee(e,t={}){let r=await N(e,t);if(r.statusCode!==200)throw new Error(`Failed to fetch text: ${r.statusCode} ${r.statusMessage}`);return new Promise((s,i)=>{let n="";r.setEncoding("utf8"),r.on("data",a=>{n+=a}),r.on("end",()=>s(n)),r.on("error",i)})}import*as te from"fs";import*as S from"path";function $e(e){let t=e;for(;;){if(te.existsSync(S.join(t,"package.json")))return t;let r=S.dirname(t);if(r===t)return e;t=r}}var re=$e(l),b=S.join(re,"bin"),dt=S.join(re,"package.json");var Me="https://github.com/iqbal-rashed/ytdlp-nodejs/releases/download/ffmpeg-latest",L={win32:{x64:["win-x64-ffmpeg.exe","win-x64-ffprobe.exe"],ia32:["win-ia32-ffmpeg.exe","win-ia32-ffprobe.exe"],arm64:["win-arm64-ffmpeg.exe","win-arm64-ffprobe.exe"]},linux:{x64:["linux-x64-ffmpeg","linux-x64-ffprobe"],arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]},darwin:{x64:["macos-x64-ffmpeg","macos-x64-ffprobe"],arm64:["macos-arm64-ffmpeg","macos-arm64-ffprobe"]},android:{arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]}};function se(){let e=process.platform,t=process.arch;if(!L[e]||!L[e][t])throw new Error(`No FFmpeg build available for platform: ${e}, architecture: ${t}`);return L[e][t]}async function Y(e){let t=e||b,r=k();if(r)return r;try{let s=se();if(!s.length)throw new Error;let i=s.map(a=>`${Me}/${a}`),n=s.map(a=>W.join(t,String(a.split("-").pop())));B.existsSync(t)||B.mkdirSync(t,{recursive:!0}),console.log("Downloading FFmpeg and FFprobe...");for(let a=0;a<s.length;a++){let o=i[a],u=n[a];console.log("Downloading...",W.basename(o)),await v(o,u)}try{for(let a of n)B.chmodSync(a,493)}catch{console.log("Note: Could not set executable permissions (likely Windows)")}return k()}catch(s){throw console.error(`Download failed: ${s}`),s}}function k(){try{let e=se();if(!e.length)throw new Error;let t=W.join(b,String(e[0].split("-").pop()));if(!B.existsSync(t))throw new Error("FFmpeg binary not found. Please download it first.");return t}catch{return}}import*as m from"fs";import*as O from"path";import Ve from"crypto";var ie="https://github.com/yt-dlp/yt-dlp/releases/latest/download",j={win32:{x64:"yt-dlp.exe",ia32:"yt-dlp_x86.exe"},linux:{x64:"yt-dlp",armv7l:"yt-dlp_linux_armv7l",aarch64:"yt-dlp_linux_aarch64",arm64:"yt-dlp"},darwin:{x64:"yt-dlp_macos",arm64:"yt-dlp_macos"},android:{arm64:"yt-dlp"}};function _e(){let e=process.platform,t=process.arch;if(!j[e]||!j[e][t])throw new Error(`No yt-dlp build available for ${e} ${t}`);return j[e][t]}async function $(e){let t=e||b,r=_e(),s=`${ie}/${r}`,i=O.join(t,r);if(m.existsSync(i))return i;console.log("Downloading yt-dlp...",s),m.existsSync(t)||m.mkdirSync(t,{recursive:!0});try{await v(s,i),console.log(`yt-dlp downloaded successfully to: ${i}`);try{m.chmodSync(i,493)}catch{console.log("Error while chmod")}return i}catch(a){throw console.error(`Download failed: ${a}`),a}}async function Ne(e){return new Promise((t,r)=>{let s=Ve.createHash("sha256"),i=m.createReadStream(e);i.on("data",n=>s.update(n)),i.on("end",()=>t(s.digest("hex"))),i.on("error",r)})}async function Le(e){try{let s=(await ee(`${ie}/SHA2-256SUMS`)).split(/\r?\n/).find(n=>n.includes(e));if(!s)return;let[i]=s.trim().split(/\s+/);return i||void 0}catch{return}}async function U(e){let t=await $(e),r=O.basename(t),s=await Le(r);if(!s)return{path:t,verified:!1};let i=await Ne(t);if(i.toLowerCase()!==s.toLowerCase())throw new Error(`Checksum mismatch for ${r}. Expected ${s}, got ${i}`);return{path:t,verified:!0,checksum:s}}function z(){let e=process.platform,t=process.arch;try{let r=j[e][t],s=O.join(b,r);if(!m.existsSync(s))throw new Error("Ytdlp binary not found. Please download it first.");return s}catch{return}}function P({url:e,options:t,ffmpegPath:r,withProgressTemplate:s,extra:i}){let n=h(t||{});return r&&n.push("--ffmpeg-location",r),s&&n.push("--progress-template",E),i&&i.length>0&&n.push(...i),e&&n.push(e),n}import{spawn as ae}from"child_process";var C=class extends Error{constructor(t,r={}){super(t),this.name="YtDlpError",this.exitCode=r.exitCode,this.stdout=r.stdout,this.stderr=r.stderr,this.args=r.args,this.hint=r.hint}};var We="yt-dlp reported a missing JavaScript runtime. Install Node.js or a supported browser runtime for full YouTube support. See README troubleshooting for details.";function ne(e){let t=e.toLowerCase();if(t.includes("javascript runtime")||t.includes("js runtime")||t.includes("node.js")||t.includes("nodejs")||t.includes("phantomjs")||t.includes("chromium")||t.includes("firefox"))return We}function M(e,t,r){let s=g(e);s&&(t?.(s),r?.(s))}function V(e,t,r={}){r.debugPrintCommandLine&&console.error(`[ytdlp-nodejs] Command: ${e} ${t.join(" ")}`);let s=ae(e,t,{shell:!1});return s.stdout.on("data",i=>{M(Buffer.from(i).toString(),void 0,n=>s.emit("progress",n))}),s.stderr.on("data",i=>{M(Buffer.from(i).toString(),void 0,n=>s.emit("progress",n))}),s}function p(e,t,r={}){return new Promise((s,i)=>{r.debugPrintCommandLine&&console.error(`[ytdlp-nodejs] Command: ${e} ${t.join(" ")}`);let n=ae(e,t,{shell:!1}),a="",o="";r.passThrough&&n.stdout.pipe(r.passThrough),n.stdout.on("data",u=>{if(r.passThrough)return;let f=Buffer.from(u).toString();a+=f,r.onStdout?.(f),M(f,r.onProgress)}),n.stderr.on("data",u=>{let f=Buffer.from(u).toString();o+=f,r.onStderr?.(f),M(f,r.onProgress)}),n.on("close",u=>{if(u===0)s({stdout:a,stderr:o,exitCode:u});else{let f=ne(o);i(new C(`yt-dlp exited with code ${u}: ${o}`,{exitCode:u??void 0,stdout:a,stderr:o,args:t,hint:f}))}}),n.on("error",u=>{i(new C(`Failed to start yt-dlp process: ${u.message}`,{args:t}))})})}function oe(e){return e.split(/\r?\n/).map(t=>t.trim()).filter(t=>t.length>0).filter(t=>!t.includes("~ytdlp-progress-"))}var Ye=[".jpg",".jpeg",".png",".webp",".gif"],Ue=[".vtt",".srt",".ass",".ssa",".sub",".lrc"];function ue(e){let t=[],r=[],s=[];for(let i of e){let n=i.toLowerCase();Ye.some(a=>n.endsWith(a))?r.push(i):Ue.some(a=>n.endsWith(a))?s.push(i):t.push(i)}return{filePaths:t,thumbnailPaths:r,subtitlePaths:s}}function fe(e){return P({url:e.url,options:e.options,ffmpegPath:e.ffmpegPath,withProgressTemplate:e.withProgressTemplate,extra:e.extra})}function le(e){let t=x(e);return t.push("--print","after_move:filepath"),t}function ze(e,t){if(!e.stdout)return;let r=[],s="";e.stdout.on("data",i=>{s+=i.toString();let n=s.split(/\r?\n/);s=n.pop()||"";for(let a of n){let o=a.trim();!o||o.includes("~ytdlp-progress-")||r.push(o)}}),e.on("close",()=>{let i=s.trim();if(i&&!i.includes("~ytdlp-progress-")&&r.push(i),r.length>0){let n=ue(r);e.emit("paths",n)}t?.(r)})}function Ke(e,t){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return V(e.binaryPath,t)}async function Je(e,t,r,s){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return(await p(e.binaryPath,t,{onStdout:r,onStderr:r,passThrough:s})).stdout}async function qe(e,t,r){let{format:s,onProgress:i,onPaths:n,...a}=r||{},o=le(s),u=fe({url:t,options:a,ffmpegPath:e.ffmpegPath,withProgressTemplate:!!i,extra:o}),f=await Je(e,u,A=>{let w=g(A);w&&i?.(w)}),d=oe(f);return n?.(d),{output:f,paths:d}}function ce(e,t,r){let{format:s,onPaths:i,...n}=r||{},a=le(s),o=fe({url:t,options:n,ffmpegPath:e.ffmpegPath,withProgressTemplate:!0,extra:a}),u=Ke(e,o);return ze(u,i),u}async function de(e,t,r){let s=await qe(e,t,r),{filePaths:i,thumbnailPaths:n,subtitlePaths:a}=ue(s.paths);return{output:s.output,filePaths:i,thumbnailPaths:n,subtitlePaths:a}}import{PassThrough as pe}from"stream";async function Ge(e,t,r,s){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return(await p(e.binaryPath,t,{passThrough:s,onProgress:r})).stdout}function me(e,t,r){let{format:s,onProgress:i,...n}=r||{},a=P({url:t,options:n,ffmpegPath:e.ffmpegPath,withProgressTemplate:!!i,extra:[...x(s),"-o","-"]}),o=new pe;return{promise:Ge(e,a,i,o),pipe:(f,d)=>o.pipe(f,d),pipeAsync:(f,d)=>new Promise((A,w)=>{let J=o.pipe(f,d);f.on("finish",()=>A(J)),f.on("error",w)})}}async function he(e,t,r){let{format:s,filename:i,metadata:n,onProgress:a,...o}=r||{},u="";if(!i)try{u=(await p(e.binaryPath,["--print","%(title)s","--no-download",t])).stdout.trim()}catch{}let f=new pe,d=[];f.on("data",D=>{d.push(Buffer.from(D))});let A=P({url:t,options:o,ffmpegPath:e.ffmpegPath,withProgressTemplate:!!a,extra:[...x(s),"-o","-"]});if(!e.binaryPath)throw new Error("Ytdlp binary not found");await p(e.binaryPath,A,{onStderr:D=>{if(a){let G=g(D);G&&a(G)}},passThrough:f});let w=X(o)||R(s)||"video/mp4",ke={"video/mp4":"mp4","video/webm":"webm","video/mkv":"mkv","audio/mp3":"mp3","audio/mpeg":"mp3","audio/m4a":"m4a","audio/aac":"aac","audio/flac":"flac","audio/wav":"wav","audio/ogg":"ogg","audio/opus":"opus"}[w]||w.split("/")[1]||"mp4",Oe=u?`${u}.${ke}`:"",q={name:i||Oe||"download",type:w,size:Buffer.concat(d).length,...n};return new File([new Uint8Array(Buffer.concat(d))],q.name,{type:q.type})}function K(e){let t=e.trim();if(!t)throw new Error("Empty JSON output from yt-dlp.");return JSON.parse(t)}async function F(e,t){if(!e.binaryPath)throw new Error("Ytdlp binary not found");return(await p(e.binaryPath,t)).stdout}async function ge(e,t,r){let s=["--dump-single-json","--quiet",...h({flatPlaylist:!0,...r}),t],i=await F(e,s);return K(i)}async function ye(e,t,r){let s=["--dump-single-json","--quiet",...h({flatPlaylist:!0,...r}),t],i=await F(e,s),n=K(i),a=n.formats||[];return{source:"json",info:n,formats:a}}async function be(e,t,r){let s=["--get-url",...h(r||{}),t],i=await F(e,s);return String(i).split(/\r?\n/).map(n=>n.trim()).filter(n=>n.length>0)}async function we(e,t){let s=await F(e,["--print","thumbnails_table","--print","playlist:thumbnails_table","--quiet",t]);return I(s)}async function xe(e,t){return await F(e,["--print","title",t])}async function Pe(e){return(await F(e,["--version"])).trim()}async function Fe(e,t,r){let s=["--print","urls",...h({flatPlaylist:!0,...r}),t],i=await F(e,s);return String(i).split(`
`)}var Ae=class{constructor(t){if(this.binaryPath=t?.binaryPath||z()||"",this.ffmpegPath=t?.ffmpegPath||k(),(!this.binaryPath||!T.existsSync(this.binaryPath))&&console.error(new Error("yt-dlp binary not found. Please install yt-dlp or specify correct binaryPath in options.")),this.ffmpegPath&&!T.existsSync(this.ffmpegPath)&&console.error(new Error(`FFmpeg binary not found at: ${this.ffmpegPath}. Please install FFmpeg or specify correct ffmpegPath.`)),process.platform!=="win32"&&this.binaryPath&&this.binaryPath.startsWith(b))try{T.chmodSync(this.binaryPath,493)}catch{}}getDownloadContext(){return{binaryPath:this.binaryPath,ffmpegPath:this.ffmpegPath}}getStreamContext(){return{binaryPath:this.binaryPath,ffmpegPath:this.ffmpegPath}}getInfoContext(){return{binaryPath:this.binaryPath}}async checkInstallationAsync(t){return new Promise((r,s)=>{if(t?.ffmpeg&&!this.ffmpegPath)return s(new Error("FFmpeg path is not set"));let i=ve(this.binaryPath,["--version"]),n=!1,a=!t?.ffmpeg;i.on("error",()=>n=!1),i.on("exit",o=>{if(n=o===0,t?.ffmpeg){let u=ve(this.ffmpegPath,["-version"]);u.on("error",()=>a=!1),u.on("exit",f=>{a=f===0,r(n&&a)})}else r(n)})})}checkInstallation(t){if(t?.ffmpeg&&!this.ffmpegPath)throw new Error("FFmpeg path is not set");let r=Se(this.binaryPath,["--version"],{stdio:"ignore"}),s=t?.ffmpeg?Se(this.ffmpegPath,["-version"],{stdio:"ignore"}):{status:0};return r.status===0&&s.status===0}async execAsync(t,r){let s=this.buildArgs(t,r||{}),i=n=>{if(r?.onData?.(n),r?.onProgress){let a=g(n);a&&r.onProgress?.(a)}};return this._executeAsync(s,i)}exec(t,r){let s=this.buildArgs(t,r||{},!0);return this._execute(s)}_execute(t){return V(this.binaryPath,t)}async _executeAsync(t,r){if(!this.binaryPath)throw new Error("Ytdlp binary not found");return(await p(this.binaryPath,t,{onStdout:r,onStderr:r})).stdout}buildArgs(t,r,s,i){return P({url:t,options:r,ffmpegPath:this.ffmpegPath,withProgressTemplate:s,extra:i})}download(t,r){return ce(this.getDownloadContext(),t,r)}async downloadAsync(t,r){return de(this.getDownloadContext(),t,r)}stream(t,r){return me(this.getStreamContext(),t,r)}async getInfoAsync(t,r){return ge(this.getInfoContext(),t,r)}async downloadAudio(t,r="mp3",s){let i=["aac","flac","mp3","m4a","opus","vorbis","wav","alac"];if(!i.includes(r))throw new Error(`Invalid audio format: ${r}. Supported: ${i.join(", ")}`);return this.downloadAsync(t,{...s,extractAudio:!0,audioFormat:r})}async downloadVideo(t,r="best",s){let i=["best","2160p","1440p","1080p","720p","480p","360p","240p","144p","highest","lowest"];if(!i.includes(r))throw new Error(`Invalid video quality: ${r}. Supported: ${i.join(", ")}`);let n=r==="best"?"bestvideo+bestaudio/best":`bestvideo[height<=${parseInt(r)||1080}]+bestaudio/best[height<=${parseInt(r)||1080}]`;return this.downloadAsync(t,{...s,format:n})}async getSubtitles(t,r){return(await this.downloadAsync(t,{...r,listSubs:!0,skipDownload:!0})).output?[]:[]}async getComments(t,r=20,s){let i=await this.downloadAsync(t,{...s,writeComments:!0,dumpSingleJson:!0,skipDownload:!0,extractorArgs:{youtube:[`max_comments=${r}`,"player_skip=webpage"]}});try{return JSON.parse(i.output).comments||[]}catch{return[]}}async getDirectUrlsAsync(t,r){return be(this.getInfoContext(),t,r)}async getFormatsAsync(t,r){return ye(this.getInfoContext(),t,r)}async getThumbnailsAsync(t){return we(this.getInfoContext(),t)}async getTitleAsync(t){return xe(this.getInfoContext(),t)}async getVersionAsync(){return Pe(this.getInfoContext())}async downloadFFmpeg(){return Y()}async getFileAsync(t,r){return he(this.getStreamContext(),t,r)}async getUrlsAsync(t,r){return Fe(this.getInfoContext(),t,r)}async updateYtDlpAsync(t){if(t?.preferBuiltIn!==!1&&this.binaryPath)try{await p(this.binaryPath,["--update"]);let o=await this.getVersionAsync().catch(()=>{});return{method:"built-in",binaryPath:this.binaryPath,version:o}}catch{}let s=t?.outDir||(this.binaryPath?He.dirname(this.binaryPath):void 0);if(t?.verifyChecksum!==!1){let o=await U(s),u=await p(o.path,["--version"]).then(f=>f.stdout.trim()).catch(()=>{});return{method:"download",binaryPath:o.path,version:u,verified:o.verified}}let n=await $(s),a=await p(n,["--version"]).then(o=>o.stdout.trim()).catch(()=>{});return{method:"download",binaryPath:n,version:a,verified:!1}}},Cr={downloadFFmpeg:Y,findFFmpegBinary:k,PROGRESS_STRING:E,getContentType:R,getFileExtension:Q,parseFormatOptions:x,stringToProgress:g,createArgs:h,extractThumbnails:I,downloadFile:v,BIN_DIR:b,downloadYtDlp:$,downloadYtDlpVerified:U,findYtdlpBinary:z};export{b as BIN_DIR,Ae as YtDlp,Cr as helpers};
{
"name": "ytdlp-nodejs",
"version": "2.3.5",
"version": "3.3.6",
"description": "A TypeScript wrapper for the yt-dlp executable",

@@ -9,3 +9,3 @@ "main": "./dist/index.js",

"bin": {
"ytdlp-nodejs": "./dist/cli.js"
"ytdlp-nodejs": "./dist/cli/index.js"
},

@@ -26,6 +26,9 @@ "exports": {

"download:ytdlp": "tsx ./src/scripts/downloadYtdlp.ts",
"download:ffmpeg": "tsx ./src/scripts/downloadFFmepg.ts",
"postdownload": "node ./dist/downloadYtdlp.js",
"download:ffmpeg": "tsx ./src/scripts/downloadFFmpeg.ts",
"postdownload": "node ./dist/scripts/downloadYtdlp.js",
"postinstall": "node -e \"process.env.INIT_CWD !== process.cwd() && require('child_process').execSync('npm run postdownload', { stdio: 'inherit' });\"",
"prepare": "husky"
"prepare": "husky",
"docs:dev": "rspress dev",
"docs:build": "rspress build",
"docs:preview": "rspress preview"
},

@@ -60,2 +63,3 @@ "keywords": [

"@eslint/js": "^9.23.0",
"@rspress/plugin-shiki": "^1.47.0",
"@types/jest": "^29.5.14",

@@ -67,2 +71,3 @@ "@types/node": "^22.13.11",

"jest": "^29.7.0",
"rspress": "^1.47.0",
"ts-jest": "^29.2.6",

@@ -69,0 +74,0 @@ "tsup": "^8.4.0",

+210
-307

@@ -1,441 +0,344 @@

> Important Note: Version 2 is finally here! 🎉 This is still in beta, so please feel free to submit feature requests. Found any bug? Please open an issue on our GitHub repository.
# ytdlp-nodejs
This Node.js module is a wrapper for [`yt-dlp`](https://github.com/yt-dlp/yt-dlp), a powerful video downloader, that allows you to download, stream, and fetch metadata for videos from various websites. The wrapper automatically downloads the `yt-dlp` binary and provides a simple interface for using its features directly within a Node.js environment.
[![npm version](https://img.shields.io/npm/v/ytdlp-nodejs.svg)](https://www.npmjs.com/package/ytdlp-nodejs)
[![License](https://img.shields.io/npm/l/ytdlp-nodejs.svg)](https://github.com/iqbal-rashed/ytdlp-nodejs/blob/main/LICENSE)
[![Documentation](https://img.shields.io/badge/docs-online-blue)](https://iqbal-rashed.github.io/ytdlp-nodejs)
A powerful Node.js wrapper for [yt-dlp](https://github.com/yt-dlp/yt-dlp) that provides a simple, type-safe interface for downloading, streaming, and fetching metadata from videos across thousands of websites.
📚 **[View Full Documentation](https://iqbal-rashed.github.io/ytdlp-nodejs)**
## Features
- 🚀 **Easy to use** - Simple API with TypeScript support
- 📥 **Download & Stream** - Download videos or stream them directly
- 📊 **Progress tracking** - Real-time download progress callbacks
- 🎵 **Audio extraction** - Extract audio in various formats (MP3, FLAC, etc.)
- 📋 **Metadata fetching** - Get video info, formats, thumbnails, and more
- 🔄 **Auto-updates** - Built-in yt-dlp binary management
- 💻 **CLI included** - Interactive and non-interactive command-line interface
- 🌐 **Node.js runtime** - Uses Node.js as the default JavaScript runtime for yt-dlp
## Installation
To install the `yt-dlp` Node.js wrapper, run:
```bash
npm i ytdlp-nodejs
npm install ytdlp-nodejs
```
This package recommends installing FFmpeg. You can manually download it from [here](https://github.com/yt-dlp/FFmpeg-Builds#ffmpeg-static-auto-builds), or you can use the [downloadFFmpeg()](#downloadffmpeg-promisevoid) function to automate the process. Also you can use cli to download.
> **Note**: FFmpeg is recommended for full functionality. Install it manually or use the built-in `downloadFFmpeg()` method.
## Usage
## Quick Start
### Importing the Package
```javascript
```typescript
import { YtDlp } from 'ytdlp-nodejs';
const ytdlp = new YtDlp();
```
### Downloading a Video
// Download a video
const result = await ytdlp.downloadAsync(
'https://youtube.com/watch?v=dQw4w9WgXcQ',
{
onProgress: (progress) => console.log(`${progress.percent}%`),
},
);
```javascript
async function downloadVideo() {
try {
const output = await ytdlp.downloadAsync(
'https://www.youtube.com/watch?v=_AL4IwHuHlY',
{
onProgress: (progress) => {
console.log(progress);
},
// others args
}
);
console.log('Download completed:', output);
} catch (error) {
console.error('Error:', error);
}
}
// Get video info
const info = await ytdlp.getInfoAsync(
'https://youtube.com/watch?v=dQw4w9WgXcQ',
);
console.log(info.title);
downloadVideo();
// Stream to file
import { createWriteStream } from 'fs';
const stream = ytdlp.stream('https://youtube.com/watch?v=dQw4w9WgXcQ');
await stream.pipeAsync(createWriteStream('video.mp4'));
```
### Streaming a Video
## CLI Usage
```javascript
import { createWriteStream } from 'fs';
### Interactive Mode
async function streamVideo() {
try {
const st = createWriteStream('video.mp4');
```bash
ytdlp-nodejs
```
const ytdlpStream = ytdlp.stream(
'https://www.youtube.com/watch?v=_AL4IwHuHlY',
{
onProgress: (progress) => {
console.log(progress);
},
// others args
}
);
### Commands
await ytdlpStream.pipeAsync(st);
```bash
# Download video
ytdlp-nodejs download <url> --format "bestvideo+bestaudio"
console.log('Download completed');
} catch (error) {
console.error('Error:', error);
}
}
# Download audio only
ytdlp-nodejs download <url> --audio-only --audio-format mp3
streamVideo();
```
# List available formats
ytdlp-nodejs formats <url>
## Class: `YtDlp`
# Get direct URLs
ytdlp-nodejs urls <url>
### `constructor(opt?)`
# Download subtitles
ytdlp-nodejs subs <url> --sub-langs en,es --sub-format srt
The constructor initializes the `YtDlp` object.
# Update yt-dlp
ytdlp-nodejs update
```
#### Parameters:
## API Reference
- `opt` (optional): Options to configure the paths for `yt-dlp` and `ffmpeg`.
- `binaryPath`: Path to the `yt-dlp` binary (optional).
- `ffmpegPath`: Path to the `ffmpeg` binary (optional).
### Constructor
#### Example:
```typescript
const ytDlp = new YtDlp({
binaryPath: 'path-to-yt-dlp',
ffmpegPath: 'path-to-ffmpeg',
const ytdlp = new YtDlp({
binaryPath?: string, // Path to yt-dlp binary
ffmpegPath?: string, // Path to ffmpeg binary
});
```
### `checkInstallationAsync(options?): Promise<boolean>`
### Download Methods
Asynchronously checks if both `yt-dlp` and optionally `ffmpeg` binaries are installed and available.
#### `downloadAsync(url, options?)`
#### Parameters:
Downloads a video asynchronously.
- `options` (optional): An object to specify if `ffmpeg` should also be checked.
- `ffmpeg`: If set to `true`, it checks if `ffmpeg` is installed.
```typescript
const result = await ytdlp.downloadAsync(url, {
format: 'bestvideo+bestaudio', // or use Format Options
output: './downloads/%(title)s.%(ext)s',
onProgress: (progress) => console.log(progress),
printPaths: true,
onPaths: (paths) => console.log('Saved to:', paths),
});
```
#### Returns:
#### `download(url, options?)`
- `Promise<boolean>`: Resolves to `true` if both `yt-dlp` and `ffmpeg` are installed (if required), otherwise `false`.
Downloads synchronously, returning a `ChildProcess` with progress events.
#### Example:
```typescript
const isInstalled = await ytDlp.checkInstallationAsync({ ffmpeg: true });
const process = ytdlp.download(url, { format: 'best' });
process.on('progress', (p) => console.log(p));
process.on('close', () => console.log('Done'));
```
### `checkInstallation(options?): boolean`
#### `downloadAudio(url, format?, options?)`
Synchronously checks if both `yt-dlp` and optionally `ffmpeg` binaries are installed and available.
Downloads audio only.
#### Parameters:
```typescript
await ytdlp.downloadAudio(url, 'mp3'); // 'aac', 'flac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav', 'alac'
```
- `options` (optional): An object to specify if `ffmpeg` should also be checked.
- `ffmpeg`: If set to `true`, it checks if `ffmpeg` is installed.
#### `downloadVideo(url, quality?, options?)`
#### Returns:
Downloads video with specific quality.
- `boolean`: `true` if both `yt-dlp` and `ffmpeg` are installed (if required), otherwise `false`.
#### Example:
```typescript
const isInstalled = ytDlp.checkInstallation({ ffmpeg: true });
await ytdlp.downloadVideo(url, '1080p'); // 'best', '2160p', '1440p', '1080p', '720p', etc.
```
### `execAsync(url, options?): Promise<string>`
### Streaming
Asynchronously executes `yt-dlp` with the provided URL and options.
#### `stream(url, options?)`
#### Parameters:
Returns a stream for piping.
- `url`: The URL of the video to download or stream.
- `options` (optional): Additional options to pass to `yt-dlp`:
- `onData`: A callback that is triggered when data is received from `yt-dlp`.
- `onProgress`: An callback function to track progess of downloading.
```typescript
const ytdlpStream = ytdlp.stream(url, {
format: { filter: 'audioandvideo', type: 'mp4', quality: 'highest' },
onProgress: (p) => console.log(p),
});
#### Returns:
// Sync pipe
ytdlpStream.pipe(writableStream);
- `Promise<string>`: Resolves to the output of the `yt-dlp` command.
// Async pipe
await ytdlpStream.pipeAsync(writableStream);
```
#### Example:
#### `getFileAsync(url, options?)`
Returns a `File` object without saving to disk.
```typescript
const result = await ytDlp.execAsync(
'https://www.youtube.com/watch?v=exampleVideoID'
);
const file = await ytdlp.getFileAsync(url, {
format: { filter: 'audioonly', type: 'mp3' },
onProgress: (p) => console.log(p),
});
console.log(file.name, file.size);
```
### `exec(url, options?): ChildProcess `
### Information Methods
Synchronously executes `yt-dlp` with the provided URL and options.
#### `getInfoAsync(url, options?)`
#### Parameters:
Fetches video/playlist metadata.
- `url`: The URL of the video to download or stream.
- `options` (optional): Additional options to pass to `yt-dlp`.
```typescript
const info = await ytdlp.getInfoAsync(url);
console.log(info.title, info.duration, info.formats);
```
#### Returns:
#### `getFormatsAsync(url, options?)`
- `ChildProcess`: The spawned child process running `yt-dlp`.
- `on('progress')`: An event to track progess of downloading.
Gets available formats using JSON output.
#### Example:
```typescript
const ytDlpProcess = ytDlp.exec(
'https://www.youtube.com/watch?v=exampleVideoID'
);
const result = await ytdlp.getFormatsAsync(url);
console.log(`Found ${result.formats.length} formats`);
```
### `download(url, options?): ChildProcess`
#### `getDirectUrlsAsync(url, options?)`
Downloads a video from the given URL.
Returns direct media URLs.
#### Parameters:
```typescript
const urls = await ytdlp.getDirectUrlsAsync(url);
```
- `url`: The URL of the video to download.
- `options` (optional): Additional options for downloading, such as video format.
- `format`: String | [Format Options](#format-options).
#### `getTitleAsync(url)`
#### Returns:
```typescript
const title = await ytdlp.getTitleAsync(url);
```
- `ChildProcess`: The spawned child process running `yt-dlp`.
- `on('progress')`: An event to track progess of downloading.
#### `getThumbnailsAsync(url)`
#### Example:
```typescript
ytDlp.download('https://www.youtube.com/watch?v=exampleVideoID', {
format: 'bestvideo+bestaudio',
});
const thumbnails = await ytdlp.getThumbnailsAsync(url);
```
### `downloadAsync(url, options?): Promise<string>`
#### `getVersionAsync()`
Asynchronously downloads a video from the given URL.
```typescript
const version = await ytdlp.getVersionAsync();
```
#### Parameters:
### Utility Methods
- `url`: The URL of the video to download.
- `options` (optional): Additional options for downloading, such as video format and a progress callback.
- `format`: String | [Format Options](#format-options).
- `onProgress`: An callback function to track progess of downloading.
- `output`: String | Custom output path and filename template. Uses [yt-dlp output template syntax](https://github.com/yt-dlp/yt-dlp#output-template). For example: `"./downloads/%(title)s.%(ext)s"`.
#### `checkInstallationAsync(options?)`
#### Returns:
```typescript
const installed = await ytdlp.checkInstallationAsync({ ffmpeg: true });
```
- `Promise<string>`: Resolves to the output of the `yt-dlp` command.
#### `downloadFFmpeg()`
#### Example:
```typescript
const result = await ytDlp.downloadAsync(
'https://www.youtube.com/watch?v=exampleVideoID',
{
format: 'bestvideo+bestaudio',
}
);
await ytdlp.downloadFFmpeg();
```
### `stream(url, options?): PipeResponse`
#### `updateYtDlpAsync(options?)`
Streams a video from the given URL.
```typescript
const result = await ytdlp.updateYtDlpAsync();
console.log(`Updated to ${result.version}`);
```
#### Parameters:
## Format Options
- `url`: The URL of the video to stream.
- `options` (optional): Additional options for streaming, such as video format and a progress callback.
- `format`: String | [Format Options](#format-options).
- `onProgress`: An callback function to track progess of downloading.
Use structured format options for type-safe configuration:
#### Returns:
```typescript
// Video only
{ filter: 'videoonly', type: 'mp4', quality: '1080p' }
- `pipe`: A function that pipes the stream to a writable stream.
- `pipeAsync`: A function that pipes the stream asynchronously to a writable stream.
// Audio only
{ filter: 'audioonly', type: 'mp3', quality: 5 }
#### Example:
// Audio and video (single file)
{ filter: 'audioandvideo', type: 'mp4', quality: 'highest' }
```typescript
const ytdlpStream = ytDlp.stream(
'https://www.youtube.com/watch?v=exampleVideoID'
);
ytdlpStream.pipe(destinationStream);
// Merge video and audio
{ filter: 'mergevideo', type: 'mp4', quality: '1080p' }
```
### `getInfoAsync(url, options?): Promise<VideoInfo | PlaylistInfo>`
### Quality Options
Fetches detailed information about a video asynchronously.
| Filter | Quality Values |
| ------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `videoonly`, `mergevideo` | `'2160p'`, `'1440p'`, `'1080p'`, `'720p'`, `'480p'`, `'360p'`, `'240p'`, `'144p'`, `'highest'`, `'lowest'` |
| `audioandvideo` | `'highest'`, `'lowest'` |
| `audioonly` | `0` to `10` (VBR quality) |
#### Parameters:
### Type Options
- `url`: The URL of the video.
- `options` (optional): InfoOptions
Additional options to control the fetching behavior:
| Filter | Type Values |
| ---------------------------- | ---------------------------------------------------------------------------- |
| `videoonly`, `audioandvideo` | `'mp4'`, `'webm'` |
| `audioonly` | `'aac'`, `'flac'`, `'mp3'`, `'m4a'`, `'opus'`, `'vorbis'`, `'wav'`, `'alac'` |
| `mergevideo` | `'mkv'`, `'mp4'`, `'ogg'`, `'webm'`, `'flv'` |
- `flatPlaylist`?: `boolean` (default: `true`) |
If `true`, returns a flat list with limited information for playlist items.
If `false`, fetches full information for each video in the playlist.
## Advanced Options
- `cookies`?: `string` |
A raw cookie header string to be used for authenticated requests.
### JavaScript Runtime
- `cookiesFromBrowser`?: `string` |
Uses cookies retrieved from the specified browser profile.
Node.js is used as the default JavaScript runtime for yt-dlp extractors:
- `noCookiesFromBrowser`?: `boolean` |
If true, disables automatically retrieving cookies from the browser.
- `noCookies`?: `boolean` |
If true, disables the use of all cookies entirely (overrides other cookie options).
#### Returns:
- `Promise<VideoInfo | PlaylistInfo>`: Resolves to a `VideoInfo` or `PlaylistInfo` object containing metadata about the video.
#### Example:
```typescript
const info = await ytDlp.getInfoAsync('url');
if (info._type == 'video') {
console.log(info); // VideoInfo
}
if (info._type == 'playlist') {
console.log(info); // PlaylistInfo
}
await ytdlp.execAsync(url, {
jsRuntime: 'node', // default, or 'deno', 'phantomjs'
});
```
### `getThumbnailsAsync(url): Promise<VideoThumbnail[]>`
### Raw Arguments
Fetches all available thumbnails for a video asynchronously.
Pass any yt-dlp argument directly:
#### Parameters:
- `url`: The URL of the video.
#### Returns:
- `Promise<VideoThumbnail[]>`: Resolves to an array of `VideoThumbnail` objects.
#### Example:
```typescript
const thumbnails = await ytDlp.getThumbnailsAsync(
'https://www.youtube.com/watch?v=exampleVideoID'
);
await ytdlp.downloadAsync(url, {
rawArgs: ['--match-filter', 'duration > 60', '--geo-bypass'],
});
```
### `getTitleAsync(url): Promise<string>`
### Debug Mode
Fetche title for a video asynchronously.
#### Parameters:
- `url`: The URL of the video.
#### Returns:
- `Promise<string>`: Resolves to a string.
#### Example:
```typescript
const title = await ytDlp.getTitleAsync(
'https://www.youtube.com/watch?v=exampleVideoID'
);
await ytdlp.execAsync(url, {
debugPrintCommandLine: true,
verbose: true,
});
```
### `getFileAsync(url, options?): Promise<File>`
## Configuration
Returns a `File` object containing the video/audio data without saving it to disk.
CLI settings are stored in an OS-specific config file:
#### Parameters:
| OS | Path |
| ------- | -------------------------------------------------------- |
| macOS | `~/Library/Application Support/ytdlp-nodejs/config.json` |
| Linux | `~/.config/ytdlp-nodejs/config.json` |
| Windows | `%APPDATA%\ytdlp-nodejs\config.json` |
- `url`: The URL of the video.
- `options` (optional): Additional options for getting the file:
- `format`: String | [Format Options](#format-options)
- `filename`: Custom filename for the resulting file
- `metadata`: Custom metadata for the file:
- `name`: File name
- `type`: MIME type
- `size`: File size in bytes
- `onProgress`: A callback function to track progress of downloading
Set `YTDLP_NODEJS_CONFIG_DIR` environment variable to override.
#### Returns:
## Troubleshooting
- `Promise<File>`: Resolves to a `File` object containing the video/audio data.
### Binary not found
#### Example:
```typescript
const file = await ytdlp.getFileAsync(
'https://www.youtube.com/watch?v=exampleVideoID',
{
format: {
filter: 'audioandvideo',
type: 'mp4',
quality: 'highest',
},
filename: 'custom-video.mp4',
onProgress: (progress) => {
console.log(progress);
},
}
);
import { helpers } from 'ytdlp-nodejs';
await helpers.downloadYtDlp();
await helpers.downloadFFmpeg();
```
### `downloadFFmpeg(): Promise<void>`
Or provide custom paths:
Downloads `ffmpeg` using a predefined method.
#### Returns:
- `Promise<void>`: Resolves once the download is complete.
#### Example:
```typescript
await ytDlp.downloadFFmpeg();
const ytdlp = new YtDlp({
binaryPath: '/path/to/yt-dlp',
ffmpegPath: '/path/to/ffmpeg',
});
```
# Format Options
## Built With ytdlp-nodejs
`filter:` "videoonly" | "audioonly" | "audioandvideo" | "mergevideo"
🚀 **[NextDownloader.com](https://nextdownloader.com/)** - A video downloader I built using this library. Check it out and let me know what you think! Your feedback is greatly appreciated.
- `filter: "videoonly"`
## Contributing
- `quality:` "2160p" |
"1440p" |
"1080p" |
"720p" |
"480p" |
"360p" |
"240p" |
"144p" |
"highest" |
"lowest" (default: 'highest')
- `type:` "mp4" | "webm" (default:'mp4')
Contributions are welcome! Please feel free to submit a Pull Request or open an issue on [GitHub](https://github.com/iqbal-rashed/ytdlp-nodejs).
- `filter: "audioonly"`
## License
- `quality:` "highest" | "lowest" (default:'highest')
- `filter: "audioandvideo"`
- `quality:` "highest" | "lowest" (default:'highest')
- `type:` "mp4" | "webm" (default:'mp4')
- `filter: "audioonly"`
- `quality:` 0 to 10 (default:5)
- `type:` "aac" | "flac" | "mp3" | "m4a" | "opus" | "vorbis" | "wav" | "alac" (default:'mp3')
- `filter: "mergevideo"`
- `quality:` "2160p" |
"1440p" |
"1080p" |
"720p" |
"480p" |
"360p" |
"240p" |
"144p" |
"highest" |
"lowest" (default: 'highest')
- `format:` "mkv" | "mp4" | "ogg" | "webm" | "flv" (default:'mp4')
## Contributing
Contributions are welcome! Feel free to submit a pull request or open an issue on GitHub.
MIT
#!/usr/bin/env node
"use strict";var R=Object.create;var A=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var C=Object.getPrototypeOf,N=Object.prototype.hasOwnProperty;var $=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of _(e))!N.call(r,a)&&a!==t&&A(r,a,{get:()=>e[a],enumerable:!(s=M(e,a))||s.enumerable});return r};var o=(r,e,t)=>(t=r!=null?R(C(r)):{},$(e||!r||!r.__esModule?A(t,"default",{value:r,enumerable:!0}):t,r));var B=require("util");var D=o(require("path"));var y=o(require("path")),g=o(require("fs"));var j=o(require("https")),L=o(require("http")),b=require("url"),f=o(require("fs"));function O(r,e={}){return new Promise((t,s)=>{let i=(new b.URL(r).protocol==="https:"?j:L).get(r,e,n=>{if(n.statusCode>=300&&n.statusCode<400&&n.headers.location){let c=new b.URL(n.headers.location,r).toString();O(c,e).then(t).catch(s);return}t(n)});i.on("error",s),i.setTimeout(3e4,()=>{i.destroy(),s(new Error("Request timed out"))})})}async function p(r,e){try{let t=f.createWriteStream(e),s=await O(r);if(s.statusCode!==200)throw t.close(),f.unlinkSync(e),new Error(`Failed to download file: ${s.statusCode} ${s.statusMessage}`);let a=parseInt(s.headers["content-length"]||"0",10),u=0;return s.on("data",i=>{u+=i.length;let n=u/a*100;process.stdout.write(`Progress: ${Math.round(n)}%\r`)}),s.pipe(t),new Promise((i,n)=>{t.on("finish",()=>{t.close(),console.log(`
Download complete!`),i()}),t.on("error",c=>{t.close(),f.unlinkSync(e),n(c)}),s.on("error",c=>{t.close(),f.unlinkSync(e),n(c)})})}catch(t){throw f.existsSync(e)&&f.unlinkSync(e),t}}var W="https://github.com/iqbal-rashed/ytdlp-nodejs/releases/download/ffmpeg-latest",w={win32:{x64:["win-x64-ffmpeg.exe","win-x64-ffprobe.exe"],ia32:["win-ia32-ffmpeg.exe","win-ia32-ffprobe.exe"],arm64:["win-arm64-ffmpeg.exe","win-arm64-ffprobe.exe"]},linux:{x64:["linux-x64-ffmpeg","linux-x64-ffprobe"],arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]},darwin:{x64:["macos-x64-ffmpeg","macos-x64-ffprobe"],arm64:["macos-arm64-ffmpeg","macos-arm64-ffprobe"]},android:{arm64:["linux-arm64-ffmpeg","linux-arm64-ffprobe"]}};function T(){let r=process.platform,e=process.arch;if(!w[r]||!w[r][e])throw new Error(`No FFmpeg build available for platform: ${r}, architecture: ${e}`);return w[r][e]}async function F(r){let e=r||h,t=x();if(t)return t;try{let s=T();if(!s.length)throw new Error;let a=s.map(i=>`${W}/${i}`),u=s.map(i=>y.default.join(e,String(i.split("-").pop())));g.default.existsSync(e)||g.default.mkdirSync(e,{recursive:!0}),console.log("Downloading FFmpeg and FFprobe...");for(let i=0;i<s.length;i++){let n=a[i],c=u[i];console.log("Downloading...",y.default.basename(n)),await p(n,c)}try{for(let i of u)g.default.chmodSync(i,493)}catch{console.log("Note: Could not set executable permissions (likely Windows)")}return x()}catch(s){throw console.error(`Download failed: ${s}`),s}}function x(){try{let r=T();if(!r.length)throw new Error;let e=y.default.join(h,String(r[0].split("-").pop()));if(!g.default.existsSync(e))throw new Error("FFmpeg binary not found. Please download it first.");return e}catch{return}}var m=o(require("fs")),I=o(require("path"));var V="https://github.com/yt-dlp/yt-dlp/releases/latest/download",v={win32:{x64:"yt-dlp.exe",ia32:"yt-dlp_x86.exe"},linux:{x64:"yt-dlp",armv7l:"yt-dlp_linux_armv7l",aarch64:"yt-dlp_linux_aarch64",arm64:"yt-dlp"},darwin:{x64:"yt-dlp_macos",arm64:"yt-dlp_macos"},android:{arm64:"yt-dlp"}};function z(){let r=process.platform,e=process.arch;if(!v[r]||!v[r][e])throw new Error(`No FFmpeg build available for ${r} ${e}`);return v[r][e]}async function k(r){let e=r||h,t=z(),s=`${V}/${t}`,a=I.join(e,t);if(m.existsSync(a))return a;console.log("Downloading yt-dlp...",s),m.existsSync(e)||m.mkdirSync(e,{recursive:!0});try{await p(s,a),console.log(`yt-dlp downloaded successfully to: ${a}`);try{m.chmodSync(a,493)}catch{console.log("Error while chmod")}return a}catch(i){throw console.error(`Download failed: ${i}`),i}}var h=D.join(__dirname,"..","bin");var P=o(require("fs")),E=o(require("path"));var U=process.argv.slice(2),{values:S}=(0,B.parseArgs)({args:U,options:{download:{type:"string",short:"d",choices:["ffmpeg","ytdlp"],default:"ffmpeg"},out:{type:"string",short:"o",default:h}}}),d=E.default.resolve(S.out);if(!P.default.existsSync(d))try{P.default.mkdirSync(d,{recursive:!0}),console.log(`Created directory: ${d}`)}catch(r){console.error(`Error creating directory ${d}:`,r),process.exit(1)}S.download=="ytdlp"?k(d):S.download=="ffmpeg"?F(d):console.error("Please select ffmpeg or ytdlp to download");
"use strict";var v=Object.create;var b=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var O=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of P(e))!A.call(r,i)&&i!==t&&b(r,i,{get:()=>e[i],enumerable:!(s=k(e,i))||s.enumerable});return r};var l=(r,e,t)=>(t=r!=null?v(S(r)):{},O(e||!r||!r.__esModule?b(t,"default",{value:r,enumerable:!0}):t,r));var u=l(require("fs")),F=l(require("path"));var T=l(require("https")),I=l(require("http")),d=require("url"),o=l(require("fs"));function w(r,e={}){return new Promise((t,s)=>{let a=(new d.URL(r).protocol==="https:"?T:I).get(r,e,n=>{if(n.statusCode>=300&&n.statusCode<400&&n.headers.location){let c=new d.URL(n.headers.location,r).toString();w(c,e).then(t).catch(s);return}t(n)});a.on("error",s),a.setTimeout(3e4,()=>{a.destroy(),s(new Error("Request timed out"))})})}async function m(r,e){try{let t=o.createWriteStream(e),s=await w(r);if(s.statusCode!==200)throw t.close(),o.unlinkSync(e),new Error(`Failed to download file: ${s.statusCode} ${s.statusMessage}`);let i=parseInt(s.headers["content-length"]||"0",10),h=0;return s.on("data",a=>{h+=a.length;let n=h/i*100;process.stdout.write(`Progress: ${Math.round(n)}%\r`)}),s.pipe(t),new Promise((a,n)=>{t.on("finish",()=>{t.close(),console.log(`
Download complete!`),a()}),t.on("error",c=>{t.close(),o.unlinkSync(e),n(c)}),s.on("error",c=>{t.close(),o.unlinkSync(e),n(c)})})}catch(t){throw o.existsSync(e)&&o.unlinkSync(e),t}}var x=l(require("path"));var p=x.join(__dirname,"..","bin");var B="https://github.com/yt-dlp/yt-dlp/releases/latest/download",y={win32:{x64:"yt-dlp.exe",ia32:"yt-dlp_x86.exe"},linux:{x64:"yt-dlp",armv7l:"yt-dlp_linux_armv7l",aarch64:"yt-dlp_linux_aarch64",arm64:"yt-dlp"},darwin:{x64:"yt-dlp_macos",arm64:"yt-dlp_macos"},android:{arm64:"yt-dlp"}};function D(){let r=process.platform,e=process.arch;if(!y[r]||!y[r][e])throw new Error(`No FFmpeg build available for ${r} ${e}`);return y[r][e]}async function g(r){let e=r||p,t=D(),s=`${B}/${t}`,i=F.join(e,t);if(u.existsSync(i))return i;console.log("Downloading yt-dlp...",s),u.existsSync(e)||u.mkdirSync(e,{recursive:!0});try{await m(s,i),console.log(`yt-dlp downloaded successfully to: ${i}`);try{u.chmodSync(i,493)}catch{console.log("Error while chmod")}return i}catch(a){throw console.error(`Download failed: ${a}`),a}}g().catch(r=>{console.error("Failed to download yt-dlp:",r),process.exit(1)});