ytdlp-nodejs
Advanced tools
| #!/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 }; |
+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 }; |
+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}); |
+4
-4
@@ -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}; |
+10
-5
| { | ||
| "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. | ||
| [](https://www.npmjs.com/package/ytdlp-nodejs) | ||
| [](https://github.com/iqbal-rashed/ytdlp-nodejs/blob/main/LICENSE) | ||
| [](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)}); |
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 3 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
227537
112.45%1650
105.99%4
-20%14
16.67%1
Infinity%345
-21.95%33
200%20
122.22%