From 3ee7273b920ef95ce24c7eab4b0876336898d064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D1=81=D0=B5=D0=B2=D0=BE=D0=BB=D0=BE=D0=B4=20=D0=9E?= =?UTF-8?q?=2E?= Date: Sat, 4 Jan 2025 14:01:10 +0300 Subject: [PATCH] api: move yt downloader to yt-dl --- api/package.json | 1 + api/src/processing/match-action.js | 3 + api/src/processing/services/youtube.js | 554 +++---------------------- pnpm-lock.yaml | 345 +++++++++++++++ 4 files changed, 401 insertions(+), 502 deletions(-) diff --git a/api/package.json b/api/package.json index 2205e1c5..b3596379 100644 --- a/api/package.json +++ b/api/package.json @@ -39,6 +39,7 @@ "set-cookie-parser": "2.6.0", "undici": "^5.19.1", "url-pattern": "1.0.3", + "youtube-dl-exec": "^3.0.12", "youtubei.js": "^12.2.0", "zod": "^3.23.8" }, diff --git a/api/src/processing/match-action.js b/api/src/processing/match-action.js index 5c728626..d1a0995b 100644 --- a/api/src/processing/match-action.js +++ b/api/src/processing/match-action.js @@ -59,6 +59,9 @@ export default function({ r, host, audioFormat, isAudioOnly, isAudioMuted, disab type: Array.isArray(r.urls) ? "merge" : "remux", isHLS: true, } + if (r.type === 'redirect') { + responseType = "redirect"; + } break; case "muteVideo": diff --git a/api/src/processing/services/youtube.js b/api/src/processing/services/youtube.js index 6559978c..0c976561 100644 --- a/api/src/processing/services/youtube.js +++ b/api/src/processing/services/youtube.js @@ -1,519 +1,69 @@ -import HLS from "hls-parser"; +import youtubedl from 'youtube-dl-exec'; +import { env } from '../../config.js'; -import { fetch } from "undici"; -import { Innertube, Session } from "youtubei.js"; - -import { env } from "../../config.js"; -import { getCookie, updateCookieValues } from "../cookie/manager.js"; - -const PLAYER_REFRESH_PERIOD = 1000 * 60 * 15; // ms - -let innertube, lastRefreshedAt; - -const codecList = { - h264: { - videoCodec: "avc1", - audioCodec: "mp4a", - container: "mp4" - }, - av1: { - videoCodec: "av01", - audioCodec: "opus", - container: "webm" - }, - vp9: { - videoCodec: "vp9", - audioCodec: "opus", - container: "webm" - } -} - -const hlsCodecList = { - h264: { - videoCodec: "avc1", - audioCodec: "mp4a", - container: "mp4" - }, - vp9: { - videoCodec: "vp09", - audioCodec: "mp4a", - container: "webm" - } -} - -const videoQualities = [144, 240, 360, 480, 720, 1080, 1440, 2160, 4320]; - -const transformSessionData = (cookie) => { - if (!cookie) - return; - - const values = { ...cookie.values() }; - const REQUIRED_VALUES = ['access_token', 'refresh_token']; - - if (REQUIRED_VALUES.some(x => typeof values[x] !== 'string')) { - return; - } - - if (values.expires) { - values.expiry_date = values.expires; - delete values.expires; - } else if (!values.expiry_date) { - return; - } - - return values; -} - -const cloneInnertube = async (customFetch) => { - const shouldRefreshPlayer = lastRefreshedAt + PLAYER_REFRESH_PERIOD < new Date(); - - const rawCookie = getCookie('youtube'); - const rawCookieValues = rawCookie?.values(); - const cookie = rawCookie?.toString(); - - if (!innertube || shouldRefreshPlayer) { - innertube = await Innertube.create({ - fetch: customFetch, - retrieve_player: !!cookie, - cookie, - po_token: rawCookieValues?.po_token, - visitor_data: rawCookieValues?.visitor_data, +export default async function(o) { + try { + const output = await youtubedl(`https://www.youtube.com/watch?v=${o.id}`, { + dumpSingleJson: true, + noCheckCertificates: true, + noWarnings: true, + addHeader: [ + 'referer:youtube.com', + 'user-agent:googlebot' + ], + downloader: 'ffmpeg', + hlsUseMpegts: true, }); - lastRefreshedAt = +new Date(); - } - const session = new Session( - innertube.session.context, - innertube.session.key, - innertube.session.api_version, - innertube.session.account_index, - innertube.session.player, - cookie, - customFetch ?? innertube.session.http.fetch, - innertube.session.cache - ); + const { is_live, duration, formats, title } = output; - const oauthCookie = getCookie('youtube_oauth'); - const oauthData = transformSessionData(oauthCookie); - - if (!session.logged_in && oauthData) { - await session.oauth.init(oauthData); - session.logged_in = true; - } - - if (session.logged_in && oauthData) { - if (session.oauth.shouldRefreshToken()) { - await session.oauth.refreshAccessToken(); + if (is_live) { + return { error: "content.video.live" }; } - const cookieValues = oauthCookie.values(); - const oldExpiry = new Date(cookieValues.expiry_date); - const newExpiry = new Date(session.oauth.oauth2_tokens.expiry_date); - - if (oldExpiry.getTime() !== newExpiry.getTime()) { - updateCookieValues(oauthCookie, { - ...session.oauth.client_id, - ...session.oauth.oauth2_tokens, - expiry_date: newExpiry.toISOString() - }); + if (duration > env.durationLimit) { + return { error: "content.too_long" }; } - } - const yt = new Innertube(session); - return yt; -} + if (formats.length === 0) { + return { error: "youtube.no_matching_format" }; + } -export default async function (o) { - let yt; - try { - yt = await cloneInnertube( - (input, init) => fetch(input, { - ...init, - dispatcher: o.dispatcher - }) - ); + const qualityDict = formats.reduce((acc, format) => { + const qualityLabel = format.height ? `${format.height}p` : "unknown"; + acc[qualityLabel] = { + url: format.url, + extension: format.ext, + resolution: format.height ? `${format.height}p` : "unknown", + youtubeFormat: format.ext + }; + return acc; + }, {}); + + return { + type: "redirect", + urls: qualityDict, + filenameAttributes: { + title, + }, + fileMetadata: {}, + isHLS: true, + }; } catch (e) { - if (e.message?.endsWith("decipher algorithm")) { - return { error: "youtube.decipher" } - } else if (e.message?.includes("refresh access token")) { - return { error: "youtube.token_expired" } - } else throw e; - } + console.error(e); - const cookie = getCookie('youtube')?.toString(); - - let useHLS = o.youtubeHLS; - - // HLS playlists don't contain the av1 video format, at least with the iOS client - if (useHLS && o.format === "av1") { - useHLS = false; - } - - let innertubeClient = "ANDROID"; - - if (cookie) { - useHLS = false; - innertubeClient = "WEB"; - } - - if (useHLS) { - innertubeClient = "IOS"; - } - - let info; - try { - info = await yt.getBasicInfo(o.id, innertubeClient); - } catch (e) { - if (e?.info) { - const errorInfo = JSON.parse(e?.info); - - if (errorInfo?.reason === "This video is private") { - return { error: "content.video.private" }; - } - if (["INVALID_ARGUMENT", "UNAUTHENTICATED"].includes(errorInfo?.error?.status)) { - return { error: "youtube.api_error" }; - } - } - - if (e?.message === "This video is unavailable") { + if (e.message.includes("This video is unavailable")) { return { error: "content.video.unavailable" }; } + if (e.message.includes("Private video")) { + return { error: "content.video.private" }; + } + + if (e.message.includes("age verification")) { + return { error: "content.video.age" }; + } + return { error: "fetch.fail" }; } - - if (!info) return { error: "fetch.fail" }; - - const playability = info.playability_status; - const basicInfo = info.basic_info; - - switch (playability.status) { - case "LOGIN_REQUIRED": - if (playability.reason.endsWith("bot")) { - return { error: "youtube.login" } - } - if (playability.reason.endsWith("age")) { - return { error: "content.video.age" } - } - if (playability?.error_screen?.reason?.text === "Private video") { - return { error: "content.video.private" } - } - break; - - case "UNPLAYABLE": - if (playability?.reason?.endsWith("request limit.")) { - return { error: "fetch.rate" } - } - if (playability?.error_screen?.subreason?.text?.endsWith("in your country")) { - return { error: "content.video.region" } - } - if (playability?.error_screen?.reason?.text === "Private video") { - return { error: "content.video.private" } - } - break; - - case "AGE_VERIFICATION_REQUIRED": - return { error: "content.video.age" }; - } - - if (playability.status !== "OK") { - return { error: "content.video.unavailable" }; - } - - if (basicInfo.is_live) { - return { error: "content.video.live" }; - } - - if (basicInfo.duration > env.durationLimit) { - return { error: "content.too_long" }; - } - - // return a critical error if returned video is "Video Not Available" - // or a similar stub by youtube - if (basicInfo.id !== o.id) { - return { - error: "fetch.fail", - critical: true - } - } - - const quality = o.quality === "max" ? 9000 : Number(o.quality); - - const normalizeQuality = res => { - const shortestSide = res.height > res.width ? res.width : res.height; - return videoQualities.find(qual => qual >= shortestSide); - } - - let video, audio, dubbedLanguage, - codec = o.format || "h264"; - - if (useHLS) { - const hlsManifest = info.streaming_data.hls_manifest_url; - - if (!hlsManifest) { - return { error: "youtube.no_hls_streams" }; - } - - const fetchedHlsManifest = await fetch(hlsManifest, { - dispatcher: o.dispatcher, - }).then(r => { - if (r.status === 200) { - return r.text(); - } else { - throw new Error("couldn't fetch the HLS playlist"); - } - }).catch(() => { }); - - if (!fetchedHlsManifest) { - return { error: "youtube.no_hls_streams" }; - } - - const variants = HLS.parse(fetchedHlsManifest).variants.sort( - (a, b) => Number(b.bandwidth) - Number(a.bandwidth) - ); - - if (!variants || variants.length === 0) { - return { error: "youtube.no_hls_streams" }; - } - - const matchHlsCodec = codecs => ( - codecs.includes(hlsCodecList[codec].videoCodec) - ); - - const best = variants.find(i => matchHlsCodec(i.codecs)); - - const preferred = variants.find(i => - matchHlsCodec(i.codecs) && normalizeQuality(i.resolution) === quality - ); - - let selected = preferred || best; - - if (!selected) { - codec = "h264"; - selected = variants.find(i => matchHlsCodec(i.codecs)); - } - - if (!selected) { - return { error: "youtube.no_matching_format" }; - } - - audio = selected.audio.find(i => i.isDefault); - - // some videos (mainly those with AI dubs) don't have any tracks marked as default - // why? god knows, but we assume that a default track is marked as such in the title - if (!audio) { - audio = selected.audio.find(i => i.name.endsWith("- original")); - } - - if (o.dubLang) { - const dubbedAudio = selected.audio.find(i => - i.language?.startsWith(o.dubLang) - ); - - if (dubbedAudio && !dubbedAudio.isDefault) { - dubbedLanguage = dubbedAudio.language; - audio = dubbedAudio; - } - } - - selected.audio = []; - selected.subtitles = []; - video = selected; - } else { - // i miss typescript so bad - const sorted_formats = { - h264: { - video: [], - audio: [], - bestVideo: undefined, - bestAudio: undefined, - }, - vp9: { - video: [], - audio: [], - bestVideo: undefined, - bestAudio: undefined, - }, - av1: { - video: [], - audio: [], - bestVideo: undefined, - bestAudio: undefined, - }, - } - - const checkFormat = (format, pCodec) => format.content_length && - (format.mime_type.includes(codecList[pCodec].videoCodec) - || format.mime_type.includes(codecList[pCodec].audioCodec)); - - // sort formats & weed out bad ones - info.streaming_data.adaptive_formats.sort((a, b) => - Number(b.bitrate) - Number(a.bitrate) - ).forEach(format => { - Object.keys(codecList).forEach(yCodec => { - const sorted = sorted_formats[yCodec]; - const goodFormat = checkFormat(format, yCodec); - if (!goodFormat) return; - - if (format.has_video) { - sorted.video.push(format); - if (!sorted.bestVideo) sorted.bestVideo = format; - } - if (format.has_audio) { - sorted.audio.push(format); - if (!sorted.bestAudio) sorted.bestAudio = format; - } - }) - }); - - const noBestMedia = () => { - const vid = sorted_formats[codec]?.bestVideo; - const aud = sorted_formats[codec]?.bestAudio; - return (!vid && !o.isAudioOnly) || (!aud && o.isAudioOnly) - }; - - if (noBestMedia()) { - if (codec === "av1") codec = "vp9"; - else if (codec === "vp9") codec = "av1"; - - // if there's no higher quality fallback, then use h264 - if (noBestMedia()) codec = "h264"; - } - - // if there's no proper combo of av1, vp9, or h264, then give up - if (noBestMedia()) { - return { error: "youtube.no_matching_format" }; - } - - audio = sorted_formats[codec].bestAudio; - - if (audio?.audio_track && !audio?.audio_track?.audio_is_default) { - audio = sorted_formats[codec].audio.find(i => - i?.audio_track?.audio_is_default - ); - } - - if (o.dubLang) { - const dubbedAudio = sorted_formats[codec].audio.find(i => - i.language?.startsWith(o.dubLang) && i.audio_track - ); - - if (dubbedAudio && !dubbedAudio?.audio_track?.audio_is_default) { - audio = dubbedAudio; - dubbedLanguage = dubbedAudio.language; - } - } - - if (!o.isAudioOnly) { - const qual = (i) => { - return normalizeQuality({ - width: i.width, - height: i.height, - }) - } - - const bestQuality = qual(sorted_formats[codec].bestVideo); - const useBestQuality = quality >= bestQuality; - - video = useBestQuality - ? sorted_formats[codec].bestVideo - : sorted_formats[codec].video.find(i => qual(i) === quality); - - if (!video) video = sorted_formats[codec].bestVideo; - } - } - - const fileMetadata = { - title: basicInfo.title.trim(), - artist: basicInfo.author.replace("- Topic", "").trim() - } - - if (basicInfo?.short_description?.startsWith("Provided to YouTube by")) { - const descItems = basicInfo.short_description.split("\n\n", 5); - - if (descItems.length === 5) { - fileMetadata.album = descItems[2]; - fileMetadata.copyright = descItems[3]; - if (descItems[4].startsWith("Released on:")) { - fileMetadata.date = descItems[4].replace("Released on: ", '').trim(); - } - } - } - - const filenameAttributes = { - service: "youtube", - id: o.id, - title: fileMetadata.title, - author: fileMetadata.artist, - youtubeDubName: dubbedLanguage || false, - } - - if (audio && o.isAudioOnly) { - let bestAudio = codec === "h264" ? "m4a" : "opus"; - let urls = audio.url; - - if (useHLS) { - bestAudio = "mp3"; - urls = audio.uri; - } - - if (innertubeClient === "WEB" && innertube) { - urls = audio.decipher(innertube.session.player); - } - - return { - type: "audio", - isAudioOnly: true, - urls, - filenameAttributes, - fileMetadata, - bestAudio, - isHLS: useHLS, - } - } - - if (video && audio) { - let resolution; - - if (useHLS) { - resolution = normalizeQuality(video.resolution); - filenameAttributes.resolution = `${video.resolution.width}x${video.resolution.height}`; - filenameAttributes.extension = hlsCodecList[codec].container; - - video = video.uri; - audio = audio.uri; - } else { - resolution = normalizeQuality({ - width: video.width, - height: video.height, - }); - - filenameAttributes.resolution = `${video.width}x${video.height}`; - filenameAttributes.extension = codecList[codec].container; - - video = video.url; - audio = audio.url; - - if (innertubeClient === "WEB" && innertube) { - video = video.decipher(innertube.session.player); - audio = audio.decipher(innertube.session.player); - } - } - - filenameAttributes.qualityLabel = `${resolution}p`; - filenameAttributes.youtubeFormat = codec; - - return { - type: "merge", - urls: [ - video, - audio, - ], - filenameAttributes, - fileMetadata, - isHLS: useHLS, - } - } - - return { error: "youtube.no_matching_format" }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c7f3b712..4ef85238 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -55,6 +55,9 @@ importers: url-pattern: specifier: 1.0.3 version: 1.0.3 + youtube-dl-exec: + specifier: ^3.0.12 + version: 3.0.12 youtubei.js: specifier: ^12.2.0 version: 12.2.0 @@ -564,6 +567,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@jclem/logfmt2@2.4.3': + resolution: {integrity: sha512-d7zluLlx+JRtVICF0+ghcrVdXBdE3eXrpIuFdcCcWxA3ABOyemkTySG4ha2AdsWFwAnh8tkB1vtyeZsWAbLumg==} + engines: {node: '>= 14.x', npm: '>= 7.x'} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -582,6 +589,10 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@kikobeats/time-span@1.0.5': + resolution: {integrity: sha512-txRAdmi35N1wnsLS1AO5mTlbY5Cv5/61WXqek2y3L9Q7u4mgdUVq819so5xe753hL5gYeLzlWoJ/VJfXg9nx8g==} + engines: {node: '>= 18'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -925,10 +936,19 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bin-version-check@6.0.0: + resolution: {integrity: sha512-k9TS/pADINX9UlErjAkbkxDer8C+WlguMwySI8sLMGLUMDvwuHmDx00yoHe7nxshgwtLBcMWQgrlwjzscUeQKg==} + engines: {node: '>=18'} + deprecated: 'Renamed to binary-version-check: https://www.npmjs.com/package/binary-version-check' + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + binary-version@7.1.0: + resolution: {integrity: sha512-Iy//vPc3ANPNlIWd242Npqc8MK0a/i4kVcHDlDA6HNMv5zMxz4ulIFhOSYJVKw/8AbHdHy0CnGYEt1QqSXxPsw==} + engines: {node: '>=18'} + body-parser@1.20.3: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -1026,6 +1046,10 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + convert-hrtime@5.0.0: + resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} + engines: {node: '>=12'} + cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} @@ -1053,6 +1077,22 @@ packages: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + d@1.0.2: + resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} + engines: {node: '>=0.12'} + + dargs@7.0.0: + resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} + engines: {node: '>=8'} + + debug-fabulous@2.0.2: + resolution: {integrity: sha512-XfAbX8/owqC+pjIg0/+3V1gp8TugJT7StX/TE1TYedjrRf7h7SgUAL/+gKoAQGPCLbSU5L5LPvDg4/cGn1E/WA==} + engines: {node: '>= 8'} + + debug-logfmt@1.2.3: + resolution: {integrity: sha512-Btc8hrSu2017BcECwhnkKtA7+9qBRv06x8igvJRRyDcZo1cmEbwp/OmLDSJFuJ/wgrdF7TbtGeVV6FCxagJoNQ==} + engines: {node: '>= 8'} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -1136,9 +1176,23 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es5-ext@0.10.64: + resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} + engines: {node: '>=0.10'} + + es6-iterator@2.0.3: + resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} + es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} + es6-symbol@3.1.4: + resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} + engines: {node: '>=0.12'} + + es6-weak-map@2.0.3: + resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} + esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -1181,6 +1235,10 @@ packages: esm-env@1.2.1: resolution: {integrity: sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==} + esniff@2.0.1: + resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} + engines: {node: '>=0.10'} + espree@10.3.0: resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1213,10 +1271,17 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + event-emitter@0.3.5: + resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + express-rate-limit@7.4.1: resolution: {integrity: sha512-KS3efpnpIDVIXopMc65EMbWbUht7qvTCdtCR2dD/IZmi9MIkopYESwyRqLgv8Pfu589+KqDqOdzJWW7AHoACeg==} engines: {node: '>= 16'} @@ -1227,6 +1292,9 @@ packages: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} + ext@1.7.0: + resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1271,6 +1339,10 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} + find-versions@6.0.0: + resolution: {integrity: sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==} + engines: {node: '>=18'} + flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -1304,6 +1376,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function-timeout@1.0.2: + resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==} + engines: {node: '>=18'} + generic-pool@3.9.0: resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==} engines: {node: '>= 4'} @@ -1316,6 +1392,10 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1393,6 +1473,10 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -1451,6 +1535,9 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-promise@2.2.2: + resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + is-reference@3.0.2: resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} @@ -1458,6 +1545,14 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-unix@2.0.10: + resolution: {integrity: sha512-CcasZSEOQUoE7JHy56se4wyRhdJfjohuMWYmceSTaDY4naKyd1fpLiY8rJsIT6AKfVstQAhHJOfPx7jcUxK61Q==} + engines: {node: '>= 12'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -1534,6 +1629,9 @@ packages: resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==} engines: {node: 20 || >=22} + lru-queue@0.1.0: + resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} + magic-string@0.30.11: resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} @@ -1549,6 +1647,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + memoizee@0.4.17: + resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==} + engines: {node: '>=0.12'} + merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -1589,6 +1691,10 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -1652,6 +1758,9 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} + next-tick@1.1.0: + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -1660,6 +1769,10 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1679,6 +1792,10 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1701,6 +1818,10 @@ packages: parse-cache-control@1.0.1: resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} + parse-ms@2.1.0: + resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} + engines: {node: '>=6'} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -1717,6 +1838,10 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} @@ -1780,6 +1905,10 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-ms@7.0.1: + resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} + engines: {node: '>=10'} + prism-svelte@0.4.7: resolution: {integrity: sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==} @@ -1869,6 +1998,14 @@ packages: sander@0.5.1: resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} + semver-regex@4.0.5: + resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==} + engines: {node: '>=12'} + + semver-truncate@3.0.0: + resolution: {integrity: sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==} + engines: {node: '>=12'} + semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} @@ -1961,6 +2098,10 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -1974,6 +2115,10 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + super-regex@1.0.0: + resolution: {integrity: sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2088,6 +2233,14 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + time-span@5.1.0: + resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} + engines: {node: '>=12'} + + timers-ext@0.1.8: + resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} + engines: {node: '>=0.12'} + tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} @@ -2095,6 +2248,10 @@ packages: resolution: {integrity: sha512-8or1+BGEdk1Zkkw2ii16qSS7uVrQJPre5A9o/XkWPATkk23FZh/15BKFxPnlTy6vkljZxLqYCzzBMj30ZrSvjw==} engines: {node: '>=12.0.0'} + tinyspawn@1.3.3: + resolution: {integrity: sha512-CvvMFgecnQMyg59nOnAD5O4lV83cVj2ooDniJ3j2bYvMajqlK4wQ13k6OUHfA+J5nkInTxbSGJv2olUJIiAtJg==} + engines: {node: '>= 18'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -2160,6 +2317,9 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + type@2.7.3: + resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} + typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} @@ -2286,6 +2446,10 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + youtube-dl-exec@3.0.12: + resolution: {integrity: sha512-CG7d0Z2RVLZhJ2IVNAauY2BtOvakd/fJq+WiZchFcaShpaQAYcajZxOZYHLej3QjiU/Exx2kR5XBUtPDtbzLwg==} + engines: {node: '>= 18'} + youtubei.js@12.2.0: resolution: {integrity: sha512-G+50qrbJCToMYhu8jbaHiS3Vf+RRul+CcDbz3hEGwHkGPh+zLiWwD6SS+YhYF+2/op4ZU5zDYQJrGqJ+wKh7Gw==} @@ -2534,6 +2698,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jclem/logfmt2@2.4.3': {} + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -2551,6 +2717,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@kikobeats/time-span@1.0.5': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2894,8 +3062,19 @@ snapshots: balanced-match@1.0.2: {} + bin-version-check@6.0.0: + dependencies: + binary-version: 7.1.0 + semver: 7.6.3 + semver-truncate: 3.0.0 + binary-extensions@2.3.0: {} + binary-version@7.1.0: + dependencies: + execa: 8.0.1 + find-versions: 6.0.0 + body-parser@1.20.3: dependencies: bytes: 3.1.2 @@ -3008,6 +3187,8 @@ snapshots: content-type@1.0.5: {} + convert-hrtime@5.0.0: {} + cookie-signature@1.0.6: {} cookie@0.6.0: {} @@ -3036,6 +3217,29 @@ snapshots: mdn-data: 2.0.30 source-map-js: 1.2.0 + d@1.0.2: + dependencies: + es5-ext: 0.10.64 + type: 2.7.3 + + dargs@7.0.0: {} + + debug-fabulous@2.0.2: + dependencies: + debug: 4.3.6 + memoizee: 0.4.17 + transitivePeerDependencies: + - supports-color + + debug-logfmt@1.2.3: + dependencies: + '@jclem/logfmt2': 2.4.3 + '@kikobeats/time-span': 1.0.5 + debug-fabulous: 2.0.2 + pretty-ms: 7.0.1 + transitivePeerDependencies: + - supports-color + debug@2.6.9: dependencies: ms: 2.0.0 @@ -3086,8 +3290,33 @@ snapshots: es-errors@1.3.0: {} + es5-ext@0.10.64: + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + esniff: 2.0.1 + next-tick: 1.1.0 + + es6-iterator@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-symbol: 3.1.4 + es6-promise@3.3.1: {} + es6-symbol@3.1.4: + dependencies: + d: 1.0.2 + ext: 1.7.0 + + es6-weak-map@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -3195,6 +3424,13 @@ snapshots: esm-env@1.2.1: {} + esniff@2.0.1: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + event-emitter: 0.3.5 + type: 2.7.3 + espree@10.3.0: dependencies: acorn: 8.14.0 @@ -3221,6 +3457,11 @@ snapshots: etag@1.8.1: {} + event-emitter@0.3.5: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + execa@5.1.1: dependencies: cross-spawn: 7.0.3 @@ -3233,6 +3474,18 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + express-rate-limit@7.4.1(express@4.21.2): dependencies: express: 4.21.2 @@ -3273,6 +3526,10 @@ snapshots: transitivePeerDependencies: - supports-color + ext@1.7.0: + dependencies: + type: 2.7.3 + fast-deep-equal@3.1.3: {} fast-glob@3.3.2: @@ -3329,6 +3586,11 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 + find-versions@6.0.0: + dependencies: + semver-regex: 4.0.5 + super-regex: 1.0.0 + flat-cache@4.0.1: dependencies: flatted: 3.3.1 @@ -3359,6 +3621,8 @@ snapshots: function-bind@1.1.2: {} + function-timeout@1.0.2: {} + generic-pool@3.9.0: optional: true @@ -3372,6 +3636,8 @@ snapshots: get-stream@6.0.1: {} + get-stream@8.0.1: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -3458,6 +3724,8 @@ snapshots: human-signals@2.1.0: {} + human-signals@5.0.0: {} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -3501,12 +3769,18 @@ snapshots: is-number@7.0.0: {} + is-promise@2.2.2: {} + is-reference@3.0.2: dependencies: '@types/estree': 1.0.5 is-stream@2.0.1: {} + is-stream@3.0.0: {} + + is-unix@2.0.10: {} + isexe@2.0.0: {} jackspeak@3.4.3: @@ -3571,6 +3845,10 @@ snapshots: lru-cache@11.0.2: {} + lru-queue@0.1.0: + dependencies: + es5-ext: 0.10.64 + magic-string@0.30.11: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -3587,6 +3865,17 @@ snapshots: media-typer@0.3.0: {} + memoizee@0.4.17: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-weak-map: 2.0.3 + event-emitter: 0.3.5 + is-promise: 2.2.2 + lru-queue: 0.1.0 + next-tick: 1.1.0 + timers-ext: 0.1.8 + merge-descriptors@1.0.3: {} merge-stream@2.0.0: {} @@ -3612,6 +3901,8 @@ snapshots: mimic-fn@2.1.0: {} + mimic-fn@4.0.0: {} + min-indent@1.0.1: {} minimatch@10.0.1: @@ -3658,12 +3949,18 @@ snapshots: negotiator@0.6.3: {} + next-tick@1.1.0: {} + normalize-path@3.0.0: {} npm-run-path@4.0.1: dependencies: path-key: 3.1.1 + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + object-assign@4.1.1: {} object-inspect@1.13.2: {} @@ -3680,6 +3977,10 @@ snapshots: dependencies: mimic-fn: 2.1.0 + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -3705,6 +4006,8 @@ snapshots: parse-cache-control@1.0.1: {} + parse-ms@2.1.0: {} + parseurl@1.3.3: {} path-exists@4.0.0: {} @@ -3713,6 +4016,8 @@ snapshots: path-key@3.1.1: {} + path-key@4.0.0: {} + path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 @@ -3757,6 +4062,10 @@ snapshots: prettier@3.3.3: {} + pretty-ms@7.0.1: + dependencies: + parse-ms: 2.1.0 + prism-svelte@0.4.7: {} prismjs@1.29.0: {} @@ -3861,6 +4170,12 @@ snapshots: mkdirp: 0.5.6 rimraf: 2.7.1 + semver-regex@4.0.5: {} + + semver-truncate@3.0.0: + dependencies: + semver: 7.6.3 + semver@7.6.3: {} send@0.19.0: @@ -3971,6 +4286,8 @@ snapshots: strip-final-newline@2.0.0: {} + strip-final-newline@3.0.0: {} + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 @@ -3987,6 +4304,11 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 + super-regex@1.0.0: + dependencies: + function-timeout: 1.0.2 + time-span: 5.1.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -4074,6 +4396,15 @@ snapshots: dependencies: any-promise: 1.3.0 + time-span@5.1.0: + dependencies: + convert-hrtime: 5.0.0 + + timers-ext@0.1.8: + dependencies: + es5-ext: 0.10.64 + next-tick: 1.1.0 + tiny-glob@0.2.9: dependencies: globalyzer: 0.1.0 @@ -4084,6 +4415,8 @@ snapshots: fdir: 6.4.0(picomatch@4.0.2) picomatch: 4.0.2 + tinyspawn@1.3.3: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -4146,6 +4479,8 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + type@2.7.3: {} + typedarray@0.0.6: {} typescript-eslint@8.18.0(eslint@9.16.0)(typescript@5.5.4): @@ -4242,6 +4577,16 @@ snapshots: yocto-queue@0.1.0: {} + youtube-dl-exec@3.0.12: + dependencies: + bin-version-check: 6.0.0 + dargs: 7.0.0 + debug-logfmt: 1.2.3 + is-unix: 2.0.10 + tinyspawn: 1.3.3 + transitivePeerDependencies: + - supports-color + youtubei.js@12.2.0: dependencies: '@bufbuild/protobuf': 2.1.0