extract-youtube 1.0.413 → 1.0.415
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2009,7 +2009,7 @@ var package_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
|
2009
2009
|
}), name, version, description, main$1, module$1, types, exports$1, bin, files, scripts, keywords, license, repository, dependencies, peerDependencies, peerDependenciesMeta, devDependencies, engines, package_default;
|
|
2010
2010
|
var init_package = require_rolldown_runtime.__esmMin((() => {
|
|
2011
2011
|
name = "extract-youtube";
|
|
2012
|
-
version = "1.0.
|
|
2012
|
+
version = "1.0.414";
|
|
2013
2013
|
description = "Fast, no-browser serverless-optimized YouTube transcript extractor, with optional React UI: a floating YouTube player and a synced-transcript modal";
|
|
2014
2014
|
main$1 = "dist/index.cjs";
|
|
2015
2015
|
module$1 = "dist/index.mjs";
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":["r","n","o","i","l","i","e","l","t","o","t","s","r"],"sources":["../src/errors/index.ts","../src/models/fetched-transcript.ts","../src/parsers/transcript-parser.ts","../src/utils/http-error-handler.ts","../src/models/transcript.ts","../src/models/transcript-list.ts","../src/types/index.ts","../src/fetchers/youtube-data-extractor.ts","../src/fetchers/transcript-list-fetcher.ts","../../../node_modules/.bun/grab-url@1.6.22/node_modules/grab-url/dist/log.es.js","../../../node_modules/.bun/grab-url@1.6.22/node_modules/grab-url/dist/core-BX1uvK6L.js","../../../node_modules/.bun/grab-url@1.6.22/node_modules/grab-url/dist/grab-api.es.js","../src/http/fetch-http-client.ts","../src/youtube-transcript-api.ts","../src/utils/transcript-utils.ts","../src/proxies/index.ts","../src/formatters/index.ts","../package.json","../src/cli.ts"],"sourcesContent":["/**\r\n * @fileoverview All error classes for the YouTube Transcript API\r\n */\r\n\r\nimport type { ProxyConfig } from '../proxies';\r\n\r\nconst YOUTUBE_WATCH_URL = 'https://www.youtube.com/watch?v={video_id}';\r\n\r\n/**\r\n * Base exception class for all YouTube Transcript API errors.\r\n */\r\nexport class YouTubeTranscriptApiException extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'YouTubeTranscriptApiException';\r\n Object.setPrototypeOf(this, YouTubeTranscriptApiException.prototype);\r\n }\r\n}\r\n\r\n/**\r\n * Base exception class for transcript retrieval errors.\r\n */\r\nexport class CouldNotRetrieveTranscript extends YouTubeTranscriptApiException {\r\n private static readonly ERROR_MESSAGE = '\\nCould not retrieve a transcript for the video {video_url}!';\r\n private static readonly CAUSE_MESSAGE_INTRO = ' This is most likely caused by:\\n\\n{cause}';\r\n private static readonly GITHUB_REFERRAL =\r\n '\\n\\nIf you are sure that the described cause is not responsible for this error ' +\r\n 'and that a transcript should be retrievable, please create an issue at ' +\r\n 'https://github.com/jdepoix/youtube-transcript-api/issues. ' +\r\n 'Please add which version of youtube_transcript_api you are using ' +\r\n 'and provide the information needed to replicate the error. ' +\r\n 'Also make sure that there are no open issues which already describe your problem!';\r\n\r\n public videoId: string;\r\n protected causeMessage: string = '';\r\n\r\n constructor(videoId: string) {\r\n super('');\r\n this.videoId = videoId;\r\n Object.setPrototypeOf(this, CouldNotRetrieveTranscript.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n\r\n protected buildErrorMessage(): string {\r\n const videoUrl = YOUTUBE_WATCH_URL.replace('{video_id}', this.videoId);\r\n let errorMessage = CouldNotRetrieveTranscript.ERROR_MESSAGE.replace('{video_url}', videoUrl);\r\n\r\n const cause = this.getCause();\r\n if (cause) {\r\n errorMessage += CouldNotRetrieveTranscript.CAUSE_MESSAGE_INTRO.replace('{cause}', cause);\r\n errorMessage += CouldNotRetrieveTranscript.GITHUB_REFERRAL;\r\n }\r\n\r\n return errorMessage;\r\n }\r\n\r\n protected getCause(): string {\r\n return this.causeMessage;\r\n }\r\n}\r\n\r\n// Cookie errors\r\nexport class CookieError extends YouTubeTranscriptApiException {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'CookieError';\r\n Object.setPrototypeOf(this, CookieError.prototype);\r\n }\r\n}\r\n\r\nexport class CookiePathInvalid extends CookieError {\r\n constructor(cookiePath: string) {\r\n super(`Can't load the provided cookie file: ${cookiePath}`);\r\n this.name = 'CookiePathInvalid';\r\n Object.setPrototypeOf(this, CookiePathInvalid.prototype);\r\n }\r\n}\r\n\r\nexport class CookieInvalid extends CookieError {\r\n constructor(cookiePath: string) {\r\n super(`The cookies provided are not valid (may have expired): ${cookiePath}`);\r\n this.name = 'CookieInvalid';\r\n Object.setPrototypeOf(this, CookieInvalid.prototype);\r\n }\r\n}\r\n\r\n// Video errors\r\nexport class YouTubeDataUnparsable extends CouldNotRetrieveTranscript {\r\n protected causeMessage =\r\n 'The data required to fetch the transcript is not parsable. This should ' +\r\n 'not happen, please open an issue (make sure to include the video ID)!';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'YouTubeDataUnparsable';\r\n Object.setPrototypeOf(this, YouTubeDataUnparsable.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class YouTubeRequestFailed extends CouldNotRetrieveTranscript {\r\n private httpErrorReason: string;\r\n\r\n constructor(videoId: string, httpError: Error) {\r\n super(videoId);\r\n this.httpErrorReason = httpError.message;\r\n this.name = 'YouTubeRequestFailed';\r\n this.message = this.buildErrorMessage();\r\n Object.setPrototypeOf(this, YouTubeRequestFailed.prototype);\r\n }\r\n\r\n protected getCause(): string {\r\n return `Request to YouTube failed: ${this.httpErrorReason}`;\r\n }\r\n}\r\n\r\nexport class VideoUnplayable extends CouldNotRetrieveTranscript {\r\n private unplayableReason: string | null;\r\n private additionalDetails: string[];\r\n\r\n constructor(videoId: string, unplayableReason: string | null, additionalDetails: string[]) {\r\n super(videoId);\r\n this.unplayableReason = unplayableReason;\r\n this.additionalDetails = additionalDetails;\r\n this.name = 'VideoUnplayable';\r\n this.message = this.buildErrorMessage();\r\n Object.setPrototypeOf(this, VideoUnplayable.prototype);\r\n }\r\n\r\n protected getCause(): string {\r\n let reason = this.unplayableReason ?? 'No reason specified!';\r\n\r\n if (this.additionalDetails.length > 0) {\r\n const formattedDetails = this.additionalDetails.map(detail => ` - ${detail}`).join('\\n');\r\n reason = `${reason}\\n\\nAdditional Details:\\n${formattedDetails}`;\r\n }\r\n\r\n return `The video is unplayable for the following reason: ${reason}`;\r\n }\r\n}\r\n\r\nexport class VideoUnavailable extends CouldNotRetrieveTranscript {\r\n protected causeMessage = 'The video is no longer available';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'VideoUnavailable';\r\n Object.setPrototypeOf(this, VideoUnavailable.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class InvalidVideoId extends CouldNotRetrieveTranscript {\r\n protected causeMessage =\r\n 'You provided an invalid video id. Make sure you are using the video id and NOT the url!\\n\\n' +\r\n 'Do NOT run: `new YouTubeTranscriptApi().fetch(\"https://www.youtube.com/watch?v=1234\")`\\n' +\r\n 'Instead run: `new YouTubeTranscriptApi().fetch(\"1234\")`';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'InvalidVideoId';\r\n Object.setPrototypeOf(this, InvalidVideoId.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class AgeRestricted extends CouldNotRetrieveTranscript {\r\n protected causeMessage =\r\n 'This video is age-restricted. Therefore, you are unable to retrieve ' +\r\n 'transcripts for it without authenticating yourself.\\n\\n' +\r\n 'Unfortunately, Cookie Authentication is temporarily unsupported in ' +\r\n 'youtube-transcript-api, as recent changes in YouTube\\'s API broke the previous ' +\r\n 'implementation. I will do my best to re-implement it as soon as possible.';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'AgeRestricted';\r\n Object.setPrototypeOf(this, AgeRestricted.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class FailedToCreateConsentCookie extends CouldNotRetrieveTranscript {\r\n protected causeMessage = 'Failed to automatically give consent to saving cookies';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'FailedToCreateConsentCookie';\r\n Object.setPrototypeOf(this, FailedToCreateConsentCookie.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\n// Transcript errors\r\nexport class TranscriptsDisabled extends CouldNotRetrieveTranscript {\r\n protected causeMessage = 'Subtitles are disabled for this video';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'TranscriptsDisabled';\r\n Object.setPrototypeOf(this, TranscriptsDisabled.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class NotTranslatable extends CouldNotRetrieveTranscript {\r\n protected causeMessage = 'The requested language is not translatable';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'NotTranslatable';\r\n Object.setPrototypeOf(this, NotTranslatable.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class TranslationLanguageNotAvailable extends CouldNotRetrieveTranscript {\r\n protected causeMessage = 'The requested translation language is not available';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'TranslationLanguageNotAvailable';\r\n Object.setPrototypeOf(this, TranslationLanguageNotAvailable.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class NoTranscriptFound extends CouldNotRetrieveTranscript {\r\n private requestedLanguageCodes: string[];\r\n private availableTranscriptData: any;\r\n\r\n constructor(videoId: string, requestedLanguageCodes: string[], availableTranscriptData: any) {\r\n super(videoId);\r\n this.requestedLanguageCodes = requestedLanguageCodes;\r\n this.availableTranscriptData = availableTranscriptData;\r\n this.name = 'NoTranscriptFound';\r\n this.message = this.buildErrorMessage();\r\n Object.setPrototypeOf(this, NoTranscriptFound.prototype);\r\n }\r\n\r\n protected getCause(): string {\r\n const requestedLanguages = this.requestedLanguageCodes.join(', ');\r\n return (\r\n `No transcripts were found for any of the requested language codes: ${requestedLanguages}\\n\\n` +\r\n this.availableTranscriptData.toString()\r\n );\r\n }\r\n}\r\n\r\nexport class PoTokenRequired extends CouldNotRetrieveTranscript {\r\n protected causeMessage =\r\n 'The requested video cannot be retrieved without a PO Token. If this happens, ' +\r\n 'please open a GitHub issue!';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'PoTokenRequired';\r\n Object.setPrototypeOf(this, PoTokenRequired.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\n// Network errors\r\nexport class RequestBlocked extends CouldNotRetrieveTranscript {\r\n private static readonly BASE_CAUSE_MESSAGE =\r\n 'YouTube is blocking requests from your IP. This usually is due to one of the ' +\r\n 'following reasons:\\n' +\r\n '- You have done too many requests and your IP has been blocked by YouTube\\n' +\r\n '- You are doing requests from an IP belonging to a cloud provider (like AWS, ' +\r\n 'Google Cloud Platform, Azure, etc.). Unfortunately, most IPs from cloud ' +\r\n 'providers are blocked by YouTube.\\n\\n';\r\n\r\n private static readonly DEFAULT_CAUSE_MESSAGE =\r\n RequestBlocked.BASE_CAUSE_MESSAGE +\r\n 'There are two things you can do to work around this:\\n' +\r\n '1. Use proxies to hide your IP address, as explained in the \"Working around ' +\r\n 'IP bans\" section of the README ' +\r\n '(https://github.com/jdepoix/youtube-transcript-api' +\r\n '?tab=readme-ov-file' +\r\n '#working-around-ip-bans-requestblocked-or-ipblocked-exception).\\n' +\r\n '2. (NOT RECOMMENDED) If you authenticate your requests using cookies, you ' +\r\n 'will be able to continue doing requests for a while. However, YouTube will ' +\r\n 'eventually permanently ban the account that you have used to authenticate ' +\r\n 'with! So only do this if you don\\'t mind your account being banned!';\r\n\r\n private static readonly WITH_GENERIC_PROXY_CAUSE_MESSAGE =\r\n 'YouTube is blocking your requests, despite you using proxies. Keep in mind ' +\r\n 'that a proxy is just a way to hide your real IP behind the IP of that proxy, ' +\r\n 'but there is no guarantee that the IP of that proxy won\\'t be blocked as ' +\r\n 'well.\\n\\n' +\r\n 'The only truly reliable way to prevent IP blocks is rotating through a large ' +\r\n 'pool of residential IPs, by using a provider like Webshare ' +\r\n '(https://www.webshare.io/?referral_code=w0xno53eb50g), which provides you ' +\r\n 'with a pool of >30M residential IPs (make sure to purchase ' +\r\n '\"Residential\" proxies, NOT \"Proxy Server\" or \"Static Residential\"!).\\n\\n' +\r\n 'You will find more information on how to easily integrate Webshare here: ' +\r\n 'https://github.com/jdepoix/youtube-transcript-api' +\r\n '?tab=readme-ov-file#using-webshare';\r\n\r\n private static readonly WITH_WEBSHARE_PROXY_CAUSE_MESSAGE =\r\n 'YouTube is blocking your requests, despite you using Webshare proxies. ' +\r\n 'Please make sure that you have purchased \"Residential\" proxies and ' +\r\n 'NOT \"Proxy Server\" or \"Static Residential\", as those won\\'t work as ' +\r\n 'reliably! The free tier also uses \"Proxy Server\" and will NOT work!\\n\\n' +\r\n 'The only reliable option is using \"Residential\" proxies (not \"Static ' +\r\n 'Residential\"), as this allows you to rotate through a pool of over 30M IPs, ' +\r\n 'which means you will always find an IP that hasn\\'t been blocked by YouTube ' +\r\n 'yet!\\n\\n' +\r\n 'You can support the development of this open source project by making your ' +\r\n 'Webshare purchases through this affiliate link: ' +\r\n 'https://www.webshare.io/?referral_code=w0xno53eb50g \\n\\n' +\r\n 'Thank you for your support! <3';\r\n\r\n private proxyConfig: ProxyConfig | null = null;\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'RequestBlocked';\r\n Object.setPrototypeOf(this, RequestBlocked.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n\r\n withProxyConfig(proxyConfig: ProxyConfig | null): RequestBlocked {\r\n this.proxyConfig = proxyConfig;\r\n this.message = this.buildErrorMessage();\r\n return this;\r\n }\r\n\r\n protected getCause(): string {\r\n // Check class name to avoid circular dependency with instanceof\r\n if (this.proxyConfig && this.proxyConfig.constructor.name === 'WebshareProxyConfig') {\r\n return RequestBlocked.WITH_WEBSHARE_PROXY_CAUSE_MESSAGE;\r\n }\r\n if (this.proxyConfig && this.proxyConfig.constructor.name === 'GenericProxyConfig') {\r\n return RequestBlocked.WITH_GENERIC_PROXY_CAUSE_MESSAGE;\r\n }\r\n return RequestBlocked.DEFAULT_CAUSE_MESSAGE;\r\n }\r\n}\r\n\r\nexport class IpBlocked extends RequestBlocked {\r\n protected causeMessage =\r\n 'YouTube is blocking requests from your IP. This usually is due to one of the ' +\r\n 'following reasons:\\n' +\r\n '- You have done too many requests and your IP has been blocked by YouTube\\n' +\r\n '- You are doing requests from an IP belonging to a cloud provider (like AWS, ' +\r\n 'Google Cloud Platform, Azure, etc.). Unfortunately, most IPs from cloud ' +\r\n 'providers are blocked by YouTube.\\n\\n' +\r\n 'Ways to work around this are explained in the \"Working around IP ' +\r\n 'bans\" section of the README (https://github.com/jdepoix/youtube-transcript-api' +\r\n '?tab=readme-ov-file' +\r\n '#working-around-ip-bans-requestblocked-or-ipblocked-exception).\\n';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'IpBlocked';\r\n Object.setPrototypeOf(this, IpBlocked.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n\r\n protected getCause(): string {\r\n return this.causeMessage;\r\n }\r\n}\r\n","/**\r\n * @fileoverview FetchedTranscript model representing a complete transcript with all snippets\r\n */\r\n\r\nimport { FetchedTranscriptSnippet } from '../types';\r\n\r\n/**\r\n * Represents a fetched transcript with all its snippets and metadata.\r\n * This class is iterable, allowing you to iterate over transcript snippets.\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcript = await api.fetch('video_id');\r\n * for (const snippet of transcript) {\r\n * console.log(snippet.text);\r\n * }\r\n * ```\r\n */\r\nexport class FetchedTranscript implements Iterable<FetchedTranscriptSnippet> {\r\n /** Array of transcript snippets */\r\n public readonly snippets: FetchedTranscriptSnippet[];\r\n\r\n /** The video ID this transcript belongs to */\r\n public readonly videoId: string;\r\n\r\n /** The language name (e.g., \"English\") */\r\n public readonly language: string;\r\n\r\n /** The language code (e.g., \"en\") */\r\n public readonly languageCode: string;\r\n\r\n /** Whether this transcript was automatically generated */\r\n public readonly isGenerated: boolean;\r\n\r\n /**\r\n * Creates a new FetchedTranscript instance.\r\n *\r\n * @param {FetchedTranscriptSnippet[]} snippets - Array of transcript snippets\r\n * @param {string} videoId - The video ID\r\n * @param {string} language - The language name\r\n * @param {string} languageCode - The language code\r\n * @param {boolean} isGenerated - Whether the transcript is auto-generated\r\n */\r\n constructor(\r\n snippets: FetchedTranscriptSnippet[],\r\n videoId: string,\r\n language: string,\r\n languageCode: string,\r\n isGenerated: boolean\r\n ) {\r\n this.snippets = snippets;\r\n this.videoId = videoId;\r\n this.language = language;\r\n this.languageCode = languageCode;\r\n this.isGenerated = isGenerated;\r\n }\r\n\r\n /**\r\n * Makes the transcript iterable, allowing for...of loops.\r\n *\r\n * @returns {Iterator<FetchedTranscriptSnippet>} Iterator over the snippets\r\n */\r\n [Symbol.iterator](): Iterator<FetchedTranscriptSnippet> {\r\n return this.snippets[Symbol.iterator]();\r\n }\r\n\r\n /**\r\n * Gets a snippet by index.\r\n *\r\n * @param {number} index - The index of the snippet\r\n * @returns {FetchedTranscriptSnippet} The snippet at the given index\r\n */\r\n getSnippetAtIndex(index: number): FetchedTranscriptSnippet {\r\n return this.snippets[index];\r\n }\r\n\r\n /**\r\n * Alias for getSnippetAtIndex() for backward compatibility.\r\n *\r\n * @deprecated Use getSnippetAtIndex() instead\r\n * @param {number} index - The index of the snippet\r\n * @returns {FetchedTranscriptSnippet} The snippet at the given index\r\n */\r\n get(index: number): FetchedTranscriptSnippet {\r\n return this.getSnippetAtIndex(index);\r\n }\r\n\r\n /**\r\n * Gets the total number of snippets in the transcript.\r\n *\r\n * @returns {number} The number of snippets\r\n */\r\n get length(): number {\r\n return this.snippets.length;\r\n }\r\n\r\n /**\r\n * Converts the transcript to raw data format (array of objects).\r\n * This is useful for serialization or when you need plain data objects.\r\n *\r\n * @returns {Array<{text: string, start: number, duration: number}>} Raw transcript data\r\n */\r\n toRawData(): Array<{ text: string; start: number; duration: number }> {\r\n return this.snippets.map(snippet => ({\r\n text: snippet.text,\r\n start: snippet.start,\r\n duration: snippet.duration\r\n }));\r\n }\r\n}\r\n","/**\r\n * @fileoverview Parser for converting YouTube transcript XML data into structured snippets\r\n */\r\n\r\nimport { XMLParser } from 'fast-xml-parser';\r\nimport { decode } from 'html-entities';\r\nimport { FetchedTranscriptSnippet } from '../types';\r\n\r\n/**\r\n * Parses transcript XML data from YouTube into FetchedTranscriptSnippet objects.\r\n *\r\n * @example\r\n * ```typescript\r\n * const parser = new TranscriptParser(false);\r\n * const snippets = parser.parseTranscriptXml(xmlData);\r\n * ```\r\n */\r\nexport class TranscriptParser {\r\n /**\r\n * HTML formatting tags that can be preserved in transcript text.\r\n * These are common formatting tags that provide semantic meaning.\r\n */\r\n private static readonly FORMATTING_TAGS = [\r\n 'strong', // Bold text\r\n 'em', // Emphasized text\r\n 'b', // Bold text (alternative)\r\n 'i', // Italic text\r\n 'mark', // Marked/highlighted text\r\n 'small', // Small text\r\n 'del', // Deleted text\r\n 'ins', // Inserted text\r\n 'sub', // Subscript\r\n 'sup' // Superscript\r\n ];\r\n\r\n private htmlRemovalRegex: RegExp;\r\n\r\n /**\r\n * Creates a new TranscriptParser instance.\r\n *\r\n * @param {boolean} [preserveFormatting=false] - Whether to preserve HTML formatting tags\r\n */\r\n constructor(preserveFormatting: boolean = false) {\r\n this.htmlRemovalRegex = this.buildHtmlRemovalRegex(preserveFormatting);\r\n }\r\n\r\n /**\r\n * Builds a regex pattern for removing HTML tags based on formatting preferences.\r\n *\r\n * @private\r\n * @param {boolean} preserveFormatting - Whether to preserve formatting tags\r\n * @returns {RegExp} The HTML removal regex\r\n */\r\n private buildHtmlRemovalRegex(preserveFormatting: boolean): RegExp {\r\n if (preserveFormatting) {\r\n // Create a regex that removes all tags EXCEPT the formatting tags\r\n const formattingTagsPattern = TranscriptParser.FORMATTING_TAGS.join('|');\r\n const pattern = `<\\\\/?(?!\\\\/?(?:${formattingTagsPattern})\\\\b).*?\\\\b>`;\r\n return new RegExp(pattern, 'gi');\r\n } else {\r\n // Remove all HTML tags\r\n return /<[^>]*>/gi;\r\n }\r\n }\r\n\r\n /**\r\n * Parses raw XML transcript data into an array of transcript snippets.\r\n *\r\n * @param {string} xmlData - The raw XML data from YouTube's transcript API\r\n * @returns {FetchedTranscriptSnippet[]} Array of parsed transcript snippets\r\n *\r\n * @example\r\n * ```typescript\r\n * const parser = new TranscriptParser();\r\n * const snippets = parser.parseTranscriptXml(xmlData);\r\n * for (const snippet of snippets) {\r\n * console.log(`${snippet.start}s: ${snippet.text}`);\r\n * }\r\n * ```\r\n */\r\n parseTranscriptXml(xmlData: string): FetchedTranscriptSnippet[] {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n attributeNamePrefix: '@_'\r\n });\r\n\r\n const parsedXml = parser.parse(xmlData);\r\n const textElements = parsedXml.transcript?.text || [];\r\n\r\n // Ensure textElements is always an array (XMLParser returns single object if only one element)\r\n const elementsArray = Array.isArray(textElements) ? textElements : [textElements];\r\n\r\n return elementsArray\r\n .filter(element => element['#text'])\r\n .map(element => this.parseTranscriptSnippet(element));\r\n }\r\n\r\n /**\r\n * Parses a single XML element into a FetchedTranscriptSnippet.\r\n *\r\n * @private\r\n * @param {any} element - The XML element to parse\r\n * @returns {FetchedTranscriptSnippet} The parsed snippet\r\n */\r\n private parseTranscriptSnippet(element: any): FetchedTranscriptSnippet {\r\n return {\r\n text: this.cleanTranscriptText(element['#text']),\r\n start: this.parseFloatAttribute(element['@_start']),\r\n duration: this.parseFloatAttribute(element['@_dur'])\r\n };\r\n }\r\n\r\n /**\r\n * Parses a string attribute as a float, defaulting to 0 if invalid.\r\n *\r\n * @private\r\n * @param {string | undefined} value - The attribute value to parse\r\n * @returns {number} The parsed float value\r\n */\r\n private parseFloatAttribute(value: string | undefined): number {\r\n return parseFloat(value || '0');\r\n }\r\n\r\n /**\r\n * Cleans transcript text by decoding HTML entities and removing HTML tags.\r\n *\r\n * @private\r\n * @param {string} text - The raw transcript text\r\n * @returns {string} The cleaned text\r\n */\r\n private cleanTranscriptText(text: string): string {\r\n // Ensure text is a string\r\n if (typeof text !== 'string') {\r\n text = String(text || '');\r\n }\r\n const decodedText = decode(text);\r\n return decodedText.replace(this.htmlRemovalRegex, '');\r\n }\r\n}\r\n","/**\r\n * @fileoverview HTTP error handling utilities for YouTube API requests\r\n */\r\n\r\nimport { IpBlocked, YouTubeRequestFailed } from '../errors';\r\n\r\n/**\r\n * Checks an HTTP response and throws appropriate errors if the request failed.\r\n *\r\n * @param {Response} response - The HTTP response to check\r\n * @param {string} videoId - The video ID associated with the request\r\n * @throws {IpBlocked} If status is 429 (Too Many Requests)\r\n * @throws {YouTubeRequestFailed} If status indicates an error\r\n *\r\n * @example\r\n * ```typescript\r\n * const response = await httpClient.get(url);\r\n * handleHttpErrors(response, videoId);\r\n * // If we reach here, the request was successful\r\n * ```\r\n */\r\nexport function handleHttpErrors(response: Response, videoId: string): void {\r\n if (response.status === 429) {\r\n throw new IpBlocked(videoId);\r\n }\r\n\r\n if (!response.ok) {\r\n const errorMessage = `HTTP ${response.status}: ${response.statusText}`;\r\n throw new YouTubeRequestFailed(videoId, new Error(errorMessage));\r\n }\r\n}\r\n","/**\r\n * @fileoverview Transcript model representing a single transcript that can be fetched or translated\r\n */\r\n\r\nimport { HttpClient, TranslationLanguage } from '../types';\r\nimport { NotTranslatable, TranslationLanguageNotAvailable, PoTokenRequired } from '../errors';\r\nimport { FetchedTranscript } from './fetched-transcript';\r\nimport { TranscriptParser } from '../parsers/transcript-parser';\r\nimport { handleHttpErrors } from '../utils/http-error-handler';\r\n\r\n/**\r\n * Represents a transcript that can be fetched or translated.\r\n * You typically obtain Transcript objects from a TranscriptList.\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcriptList = await api.list('video_id');\r\n * const transcript = transcriptList.findTranscript(['en']);\r\n * const fetched = await transcript.fetch();\r\n * ```\r\n */\r\nexport class Transcript {\r\n private httpClient: HttpClient;\r\n\r\n /** The video ID this transcript belongs to */\r\n public readonly videoId: string;\r\n\r\n private transcriptUrl: string;\r\n\r\n /** The language name (e.g., \"English\") */\r\n public readonly language: string;\r\n\r\n /** The language code (e.g., \"en\") */\r\n public readonly languageCode: string;\r\n\r\n /** Whether this transcript was automatically generated */\r\n public readonly isGenerated: boolean;\r\n\r\n /** Available translation languages */\r\n public readonly translationLanguages: TranslationLanguage[];\r\n\r\n private translationLanguagesMap: Record<string, string>;\r\n\r\n /**\r\n * Creates a new Transcript instance.\r\n * You probably don't want to initialize this directly.\r\n * Usually you'll access Transcript objects using a TranscriptList.\r\n *\r\n * @param {HttpClient} httpClient - HTTP client for making requests\r\n * @param {string} videoId - The video ID\r\n * @param {string} transcriptUrl - The transcript URL\r\n * @param {string} language - The language name\r\n * @param {string} languageCode - The language code\r\n * @param {boolean} isGenerated - Whether the transcript is auto-generated\r\n * @param {TranslationLanguage[]} translationLanguages - Available translation languages\r\n */\r\n constructor(\r\n httpClient: HttpClient,\r\n videoId: string,\r\n transcriptUrl: string,\r\n language: string,\r\n languageCode: string,\r\n isGenerated: boolean,\r\n translationLanguages: TranslationLanguage[]\r\n ) {\r\n this.httpClient = httpClient;\r\n this.videoId = videoId;\r\n this.transcriptUrl = transcriptUrl;\r\n this.language = language;\r\n this.languageCode = languageCode;\r\n this.isGenerated = isGenerated;\r\n this.translationLanguages = translationLanguages;\r\n this.translationLanguagesMap = this.buildTranslationLanguagesMap(translationLanguages);\r\n }\r\n\r\n /**\r\n * Builds a map of language codes to language names for quick lookup.\r\n *\r\n * @private\r\n * @param {TranslationLanguage[]} languages - Array of translation languages\r\n * @returns {Record<string, string>} Map of language code to language name\r\n */\r\n private buildTranslationLanguagesMap(languages: TranslationLanguage[]): Record<string, string> {\r\n const map: Record<string, string> = {};\r\n for (const lang of languages) {\r\n map[lang.language_code] = lang.language;\r\n }\r\n return map;\r\n }\r\n\r\n /**\r\n * Loads the actual transcript data from YouTube.\r\n *\r\n * @param {boolean} [preserveFormatting=false] - Whether to keep select HTML text formatting\r\n * @returns {Promise<FetchedTranscript>} The fetched transcript with all snippets\r\n * @throws {PoTokenRequired} If a PO Token is required for this video\r\n * @throws {YouTubeRequestFailed} If the HTTP request fails\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcript = transcriptList.findTranscript(['en']);\r\n * const fetched = await transcript.fetch();\r\n *\r\n * // With formatting preserved\r\n * const fetchedWithFormatting = await transcript.fetch(true);\r\n * ```\r\n */\r\n async fetch(preserveFormatting: boolean = false): Promise<FetchedTranscript> {\r\n if (this.transcriptUrl.includes('&exp=xpe')) {\r\n throw new PoTokenRequired(this.videoId);\r\n }\r\n\r\n const response = await this.httpClient.get(this.transcriptUrl);\r\n handleHttpErrors(response, this.videoId);\r\n\r\n const xmlData = await response.text();\r\n const parser = new TranscriptParser(preserveFormatting);\r\n const snippets = parser.parseTranscriptXml(xmlData);\r\n\r\n return new FetchedTranscript(\r\n snippets,\r\n this.videoId,\r\n this.language,\r\n this.languageCode,\r\n this.isGenerated\r\n );\r\n }\r\n\r\n /**\r\n * Checks whether this transcript can be translated to other languages.\r\n *\r\n * @returns {boolean} True if the transcript supports translation\r\n */\r\n get isTranslatable(): boolean {\r\n return this.translationLanguages.length > 0;\r\n }\r\n\r\n /**\r\n * Creates a translated version of this transcript.\r\n *\r\n * @param {string} targetLanguageCode - The target language code (e.g., 'de', 'fr')\r\n * @returns {Transcript} A new Transcript object for the translated transcript\r\n * @throws {NotTranslatable} If the transcript cannot be translated\r\n * @throws {TranslationLanguageNotAvailable} If the requested language is not available\r\n *\r\n * @example\r\n * ```typescript\r\n * const englishTranscript = transcriptList.findTranscript(['en']);\r\n * if (englishTranscript.isTranslatable) {\r\n * const germanTranscript = englishTranscript.translate('de');\r\n * const fetched = await germanTranscript.fetch();\r\n * }\r\n * ```\r\n */\r\n translate(targetLanguageCode: string): Transcript {\r\n if (!this.isTranslatable) {\r\n throw new NotTranslatable(this.videoId);\r\n }\r\n\r\n if (!(targetLanguageCode in this.translationLanguagesMap)) {\r\n throw new TranslationLanguageNotAvailable(this.videoId);\r\n }\r\n\r\n const translatedUrl = `${this.transcriptUrl}&tlang=${targetLanguageCode}`;\r\n const translatedLanguage = this.translationLanguagesMap[targetLanguageCode];\r\n\r\n return new Transcript(\r\n this.httpClient,\r\n this.videoId,\r\n translatedUrl,\r\n translatedLanguage,\r\n targetLanguageCode,\r\n true,\r\n [] // Translated transcripts cannot be translated again\r\n );\r\n }\r\n\r\n /**\r\n * Returns a string representation of the transcript.\r\n *\r\n * @returns {string} A formatted string representation\r\n */\r\n toString(): string {\r\n const translatableFlag = this.isTranslatable ? '[TRANSLATABLE]' : '';\r\n return `${this.languageCode} (\"${this.language}\")${translatableFlag}`;\r\n }\r\n}\r\n","/**\r\n * @fileoverview TranscriptList model representing all available transcripts for a video\r\n */\r\n\r\nimport { HttpClient, TranslationLanguage, CaptionsJson } from '../types';\r\nimport { Transcript } from './transcript';\r\nimport { NoTranscriptFound } from '../errors';\r\n\r\n/**\r\n * Represents a list of available transcripts for a video.\r\n * This object is iterable and provides methods to search for specific transcripts.\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcriptList = await api.list('video_id');\r\n *\r\n * // Iterate over all transcripts\r\n * for (const transcript of transcriptList) {\r\n * console.log(transcript.language, transcript.languageCode);\r\n * }\r\n *\r\n * // Find a specific transcript\r\n * const transcript = transcriptList.findTranscript(['de', 'en']);\r\n * ```\r\n */\r\nexport class TranscriptList implements Iterable<Transcript> {\r\n /** The video ID this list belongs to */\r\n public readonly videoId: string;\r\n\r\n private manuallyCreatedTranscripts: Record<string, Transcript>;\r\n private autoGeneratedTranscripts: Record<string, Transcript>;\r\n private availableTranslationLanguages: TranslationLanguage[];\r\n\r\n /**\r\n * Creates a new TranscriptList instance.\r\n * The constructor is only for internal use. Use the static buildFromCaptionsJson method instead.\r\n *\r\n * @param {string} videoId - The video ID\r\n * @param {Record<string, Transcript>} manuallyCreatedTranscripts - Map of manually created transcripts\r\n * @param {Record<string, Transcript>} autoGeneratedTranscripts - Map of auto-generated transcripts\r\n * @param {TranslationLanguage[]} availableTranslationLanguages - Available translation languages\r\n */\r\n constructor(\r\n videoId: string,\r\n manuallyCreatedTranscripts: Record<string, Transcript>,\r\n autoGeneratedTranscripts: Record<string, Transcript>,\r\n availableTranslationLanguages: TranslationLanguage[]\r\n ) {\r\n this.videoId = videoId;\r\n this.manuallyCreatedTranscripts = manuallyCreatedTranscripts;\r\n this.autoGeneratedTranscripts = autoGeneratedTranscripts;\r\n this.availableTranslationLanguages = availableTranslationLanguages;\r\n }\r\n\r\n /**\r\n * Factory method to build a TranscriptList from YouTube's captions JSON data.\r\n *\r\n * @param {HttpClient} httpClient - HTTP client for making requests\r\n * @param {string} videoId - The video ID\r\n * @param {CaptionsJson} captionsJson - The JSON parsed from YouTube's response\r\n * @returns {TranscriptList} The created TranscriptList\r\n */\r\n static buildFromCaptionsJson(\r\n httpClient: HttpClient,\r\n videoId: string,\r\n captionsJson: CaptionsJson\r\n ): TranscriptList {\r\n const translationLanguages = TranscriptList.extractTranslationLanguages(captionsJson);\r\n const { manualTranscripts, generatedTranscripts } = TranscriptList.categorizeTranscripts(\r\n httpClient,\r\n videoId,\r\n captionsJson,\r\n translationLanguages\r\n );\r\n\r\n return new TranscriptList(videoId, manualTranscripts, generatedTranscripts, translationLanguages);\r\n }\r\n\r\n /**\r\n * Extracts translation languages from the captions JSON.\r\n *\r\n * @private\r\n * @param {CaptionsJson} captionsJson - The captions JSON data\r\n * @returns {TranslationLanguage[]} Array of translation languages\r\n */\r\n private static extractTranslationLanguages(captionsJson: CaptionsJson): TranslationLanguage[] {\r\n return (captionsJson.translationLanguages || []).map(lang => ({\r\n language: lang.languageName.runs[0].text,\r\n language_code: lang.languageCode\r\n }));\r\n }\r\n\r\n /**\r\n * Categorizes transcripts into manually created and auto-generated.\r\n *\r\n * @private\r\n * @param {HttpClient} httpClient - HTTP client for making requests\r\n * @param {string} videoId - The video ID\r\n * @param {CaptionsJson} captionsJson - The captions JSON data\r\n * @param {TranslationLanguage[]} translationLanguages - Available translation languages\r\n * @returns {{manualTranscripts: Record<string, Transcript>, generatedTranscripts: Record<string, Transcript>}}\r\n */\r\n private static categorizeTranscripts(\r\n httpClient: HttpClient,\r\n videoId: string,\r\n captionsJson: CaptionsJson,\r\n translationLanguages: TranslationLanguage[]\r\n ): {\r\n manualTranscripts: Record<string, Transcript>;\r\n generatedTranscripts: Record<string, Transcript>;\r\n } {\r\n const manualTranscripts: Record<string, Transcript> = {};\r\n const generatedTranscripts: Record<string, Transcript> = {};\r\n\r\n for (const captionTrack of captionsJson.captionTracks) {\r\n const isAutoGenerated = captionTrack.kind === 'asr';\r\n const targetMap = isAutoGenerated ? generatedTranscripts : manualTranscripts;\r\n\r\n // Remove format parameter from URL for better compatibility\r\n const cleanedUrl = captionTrack.baseUrl.replace('&fmt=srv3', '');\r\n\r\n const transcript = new Transcript(\r\n httpClient,\r\n videoId,\r\n cleanedUrl,\r\n captionTrack.name.runs[0].text,\r\n captionTrack.languageCode,\r\n isAutoGenerated,\r\n captionTrack.isTranslatable ? translationLanguages : []\r\n );\r\n\r\n targetMap[captionTrack.languageCode] = transcript;\r\n }\r\n\r\n return { manualTranscripts, generatedTranscripts };\r\n }\r\n\r\n /**\r\n * Makes the transcript list iterable, allowing for...of loops.\r\n * Manual transcripts are yielded first, followed by auto-generated transcripts.\r\n *\r\n * @returns {Iterator<Transcript>} Iterator over all transcripts\r\n */\r\n [Symbol.iterator](): Iterator<Transcript> {\r\n const manualTranscripts = Object.values(this.manuallyCreatedTranscripts);\r\n const generatedTranscripts = Object.values(this.autoGeneratedTranscripts);\r\n return [...manualTranscripts, ...generatedTranscripts][Symbol.iterator]();\r\n }\r\n\r\n /**\r\n * Finds a transcript for given language codes. Manually created transcripts are\r\n * returned first and only if none are found, auto-generated transcripts are used.\r\n *\r\n * @param {string[]} languageCodes - A list of language codes in descending priority\r\n * @returns {Transcript} The found transcript\r\n * @throws {NoTranscriptFound} If no transcript is found for any of the language codes\r\n *\r\n * @example\r\n * ```typescript\r\n * // Try German first, then English\r\n * const transcript = transcriptList.findTranscript(['de', 'en']);\r\n * ```\r\n */\r\n findTranscript(languageCodes: string[]): Transcript {\r\n return this.findTranscriptInMaps(languageCodes, [\r\n this.manuallyCreatedTranscripts,\r\n this.autoGeneratedTranscripts\r\n ]);\r\n }\r\n\r\n /**\r\n * Finds an automatically generated transcript for given language codes.\r\n *\r\n * @param {string[]} languageCodes - A list of language codes in descending priority\r\n * @returns {Transcript} The found auto-generated transcript\r\n * @throws {NoTranscriptFound} If no auto-generated transcript is found\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcript = transcriptList.findGeneratedTranscript(['en']);\r\n * ```\r\n */\r\n findGeneratedTranscript(languageCodes: string[]): Transcript {\r\n return this.findTranscriptInMaps(languageCodes, [this.autoGeneratedTranscripts]);\r\n }\r\n\r\n /**\r\n * Finds a manually created transcript for given language codes.\r\n *\r\n * @param {string[]} languageCodes - A list of language codes in descending priority\r\n * @returns {Transcript} The found manually created transcript\r\n * @throws {NoTranscriptFound} If no manually created transcript is found\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcript = transcriptList.findManuallyCreatedTranscript(['en']);\r\n * ```\r\n */\r\n findManuallyCreatedTranscript(languageCodes: string[]): Transcript {\r\n return this.findTranscriptInMaps(languageCodes, [this.manuallyCreatedTranscripts]);\r\n }\r\n\r\n /**\r\n * Internal method to find a transcript by searching through provided maps.\r\n *\r\n * @private\r\n * @param {string[]} languageCodes - Language codes to search for\r\n * @param {Record<string, Transcript>[]} transcriptMaps - Maps to search through\r\n * @returns {Transcript} The found transcript\r\n * @throws {NoTranscriptFound} If no transcript is found\r\n */\r\n private findTranscriptInMaps(\r\n languageCodes: string[],\r\n transcriptMaps: Record<string, Transcript>[]\r\n ): Transcript {\r\n for (const languageCode of languageCodes) {\r\n for (const transcriptMap of transcriptMaps) {\r\n if (languageCode in transcriptMap) {\r\n return transcriptMap[languageCode];\r\n }\r\n }\r\n }\r\n\r\n throw new NoTranscriptFound(this.videoId, languageCodes, this);\r\n }\r\n\r\n /**\r\n * Returns a formatted string representation of all available transcripts.\r\n *\r\n * @returns {string} A formatted string showing all available transcripts\r\n */\r\n toString(): string {\r\n const formatTranscriptMap = (transcripts: Record<string, Transcript>): string => {\r\n const descriptions = Object.values(transcripts).map(t => ` - ${t.toString()}`);\r\n return descriptions.length > 0 ? descriptions.join('\\n') : 'None';\r\n };\r\n\r\n const formatTranslationLanguages = (): string => {\r\n const descriptions = this.availableTranslationLanguages.map(\r\n lang => ` - ${lang.language_code} (\"${lang.language}\")`\r\n );\r\n return descriptions.length > 0 ? descriptions.join('\\n') : 'None';\r\n };\r\n\r\n return (\r\n `For this video (${this.videoId}) transcripts are available in the following languages:\\n\\n` +\r\n `(MANUALLY CREATED)\\n${formatTranscriptMap(this.manuallyCreatedTranscripts)}\\n\\n` +\r\n `(GENERATED)\\n${formatTranscriptMap(this.autoGeneratedTranscripts)}\\n\\n` +\r\n `(TRANSLATION LANGUAGES)\\n${formatTranslationLanguages()}`\r\n );\r\n }\r\n}\r\n","/**\r\n * @fileoverview Type definitions for the YouTube Transcript API\r\n */\r\n\r\n/**\r\n * Represents a single snippet/cue of a transcript\r\n */\r\nexport interface FetchedTranscriptSnippet {\r\n /** The text content of this transcript snippet */\r\n text: string;\r\n /** The timestamp at which this transcript snippet appears on screen in seconds */\r\n start: number;\r\n /**\r\n * The duration of how long the snippet stays on screen in seconds.\r\n * Note: This is not the duration of the transcribed speech, but how long\r\n * the snippet stays on screen. Therefore, there can be overlaps between snippets!\r\n */\r\n duration: number;\r\n}\r\n\r\n/**\r\n * Translation language information\r\n */\r\nexport interface TranslationLanguage {\r\n /** The name of the language */\r\n language: string;\r\n /** The language code (e.g., 'en', 'de', 'fr') */\r\n language_code: string;\r\n}\r\n\r\n/**\r\n * Playability status enum values\r\n */\r\nexport enum PlayabilityStatus {\r\n OK = 'OK',\r\n ERROR = 'ERROR',\r\n LOGIN_REQUIRED = 'LOGIN_REQUIRED'\r\n}\r\n\r\n/**\r\n * Playability failed reason enum values\r\n */\r\nexport enum PlayabilityFailedReason {\r\n BOT_DETECTED = \"Sign in to confirm you're not a bot\",\r\n AGE_RESTRICTED = 'This video may be inappropriate for some users.',\r\n VIDEO_UNAVAILABLE = 'This video is unavailable'\r\n}\r\n\r\n/**\r\n * Proxy configuration dictionary for HTTP clients\r\n */\r\nexport interface RequestsProxyConfigDict {\r\n http: string;\r\n https: string;\r\n}\r\n\r\n/**\r\n * Caption track data from YouTube API\r\n */\r\nexport interface CaptionTrack {\r\n baseUrl: string;\r\n name: {\r\n runs: Array<{ text: string }>;\r\n };\r\n languageCode: string;\r\n kind?: string;\r\n isTranslatable?: boolean;\r\n}\r\n\r\n/**\r\n * Captions JSON data from YouTube\r\n */\r\nexport interface CaptionsJson {\r\n captionTracks: CaptionTrack[];\r\n translationLanguages?: Array<{\r\n languageName: {\r\n runs: Array<{ text: string }>;\r\n };\r\n languageCode: string;\r\n }>;\r\n}\r\n\r\n/**\r\n * YouTube InnerTube API response\r\n */\r\nexport interface InnerTubeData {\r\n playabilityStatus?: {\r\n status?: string;\r\n reason?: string;\r\n errorScreen?: {\r\n playerErrorMessageRenderer?: {\r\n subreason?: {\r\n runs?: Array<{ text?: string }>;\r\n };\r\n };\r\n };\r\n };\r\n captions?: {\r\n playerCaptionsTracklistRenderer?: CaptionsJson;\r\n };\r\n}\r\n\r\n/**\r\n * HTTP client interface with fetch-like API\r\n */\r\nexport interface HttpClient {\r\n get(url: string, options?: RequestInit): Promise<Response>;\r\n post(url: string, options?: RequestInit): Promise<Response>;\r\n}\r\n\r\n/**\r\n * Cookie storage interface\r\n */\r\nexport interface CookieJar {\r\n set(name: string, value: string, domain: string): void;\r\n get(name: string): string | undefined;\r\n}\r\n","/**\r\n * @fileoverview Utilities for extracting data from YouTube HTML and InnerTube API responses\r\n */\r\n\r\nimport {\r\n InnerTubeData,\r\n CaptionsJson,\r\n PlayabilityStatus,\r\n PlayabilityFailedReason\r\n} from '../types';\r\nimport {\r\n IpBlocked,\r\n YouTubeDataUnparsable,\r\n TranscriptsDisabled,\r\n RequestBlocked,\r\n AgeRestricted,\r\n VideoUnavailable,\r\n InvalidVideoId,\r\n VideoUnplayable\r\n} from '../errors';\r\n\r\n/**\r\n * Extracts the InnerTube API key from YouTube's HTML page.\r\n *\r\n * @param {string} htmlContent - The HTML content from YouTube's watch page\r\n * @param {string} videoId - The video ID being processed\r\n * @returns {string} The extracted API key\r\n * @throws {IpBlocked} If the page contains a reCAPTCHA (IP is blocked)\r\n * @throws {YouTubeDataUnparsable} If the API key cannot be found\r\n *\r\n * @example\r\n * ```typescript\r\n * const html = await fetchVideoHtml(videoId);\r\n * const apiKey = extractInnertubeApiKey(html, videoId);\r\n * ```\r\n */\r\nexport function extractInnertubeApiKey(htmlContent: string, videoId: string): string {\r\n const apiKeyPattern = /\"INNERTUBE_API_KEY\":\\s*\"([a-zA-Z0-9_-]+)\"/;\r\n const match = htmlContent.match(apiKeyPattern);\r\n\r\n if (match && match.length === 2) {\r\n return match[1];\r\n }\r\n\r\n // Check if IP is blocked (reCAPTCHA present)\r\n if (htmlContent.includes('class=\"g-recaptcha\"')) {\r\n throw new IpBlocked(videoId);\r\n }\r\n\r\n throw new YouTubeDataUnparsable(videoId);\r\n}\r\n\r\n/**\r\n * Extracts captions JSON from YouTube's InnerTube API response.\r\n *\r\n * @param {InnerTubeData} innertubeData - The InnerTube API response data\r\n * @param {string} videoId - The video ID being processed\r\n * @returns {CaptionsJson} The extracted captions data\r\n * @throws {TranscriptsDisabled} If captions are disabled for the video\r\n *\r\n * @example\r\n * ```typescript\r\n * const innertubeData = await fetchInnertubeData(videoId, apiKey);\r\n * const captionsJson = extractCaptionsJson(innertubeData, videoId);\r\n * ```\r\n */\r\nexport function extractCaptionsJson(innertubeData: InnerTubeData, videoId: string): CaptionsJson {\r\n validatePlayabilityStatus(innertubeData.playabilityStatus, videoId);\r\n\r\n const captionsJson = innertubeData.captions?.playerCaptionsTracklistRenderer;\r\n\r\n if (!captionsJson || !captionsJson.captionTracks) {\r\n throw new TranscriptsDisabled(videoId);\r\n }\r\n\r\n return captionsJson;\r\n}\r\n\r\n/**\r\n * Validates the playability status of a video and throws appropriate errors.\r\n *\r\n * @param {any} playabilityStatusData - The playability status data from InnerTube\r\n * @param {string} videoId - The video ID being validated\r\n * @throws {RequestBlocked} If YouTube detected a bot\r\n * @throws {AgeRestricted} If the video is age-restricted\r\n * @throws {VideoUnavailable} If the video is unavailable\r\n * @throws {InvalidVideoId} If the video ID is invalid (URL was provided instead)\r\n * @throws {VideoUnplayable} If the video is unplayable for any other reason\r\n *\r\n * @example\r\n * ```typescript\r\n * validatePlayabilityStatus(innertubeData.playabilityStatus, videoId);\r\n * ```\r\n */\r\nexport function validatePlayabilityStatus(playabilityStatusData: any, videoId: string): void {\r\n if (!playabilityStatusData) {\r\n return;\r\n }\r\n\r\n const playabilityStatus = playabilityStatusData.status;\r\n\r\n // If status is OK, video is playable\r\n if (playabilityStatus === PlayabilityStatus.OK || !playabilityStatus) {\r\n return;\r\n }\r\n\r\n const reason = playabilityStatusData.reason;\r\n\r\n // Handle LOGIN_REQUIRED status\r\n if (playabilityStatus === PlayabilityStatus.LOGIN_REQUIRED) {\r\n if (reason === PlayabilityFailedReason.BOT_DETECTED) {\r\n throw new RequestBlocked(videoId);\r\n }\r\n if (reason === PlayabilityFailedReason.AGE_RESTRICTED) {\r\n throw new AgeRestricted(videoId);\r\n }\r\n }\r\n\r\n // Handle ERROR status\r\n if (playabilityStatus === PlayabilityStatus.ERROR && reason === PlayabilityFailedReason.VIDEO_UNAVAILABLE) {\r\n // Check if user provided a URL instead of video ID\r\n if (videoId.startsWith('http://') || videoId.startsWith('https://')) {\r\n throw new InvalidVideoId(videoId);\r\n }\r\n throw new VideoUnavailable(videoId);\r\n }\r\n\r\n // Extract additional sub-reasons if available\r\n const subReasons = extractPlayabilitySubreasons(playabilityStatusData);\r\n\r\n throw new VideoUnplayable(videoId, reason, subReasons);\r\n}\r\n\r\n/**\r\n * Extracts sub-reasons from the playability status error screen.\r\n *\r\n * @private\r\n * @param {any} playabilityStatusData - The playability status data\r\n * @returns {string[]} Array of sub-reason messages\r\n */\r\nfunction extractPlayabilitySubreasons(playabilityStatusData: any): string[] {\r\n const runs = playabilityStatusData.errorScreen?.playerErrorMessageRenderer?.subreason?.runs;\r\n\r\n if (!runs || !Array.isArray(runs)) {\r\n return [];\r\n }\r\n\r\n return runs\r\n .map((run: any) => run.text || '')\r\n .filter((text: string) => text.length > 0);\r\n}\r\n","/**\r\n * @fileoverview Fetcher for retrieving transcript lists from YouTube\r\n */\r\n\r\nimport { decode } from 'html-entities';\r\nimport { HttpClient, CaptionsJson, InnerTubeData } from '../types';\r\nimport { ProxyConfig } from '../proxies';\r\nimport { TranscriptList } from '../models/transcript-list';\r\nimport { RequestBlocked, FailedToCreateConsentCookie } from '../errors';\r\nimport { handleHttpErrors } from '../utils/http-error-handler';\r\nimport {\r\n extractInnertubeApiKey,\r\n extractCaptionsJson\r\n} from './youtube-data-extractor';\r\n\r\n/** YouTube watch page URL template */\r\nconst YOUTUBE_WATCH_URL = 'https://www.youtube.com/watch?v={video_id}';\r\n\r\n/** YouTube InnerTube API URL template */\r\nconst INNERTUBE_API_URL = 'https://www.youtube.com/youtubei/v1/player?key={api_key}';\r\n\r\n/** InnerTube API context configuration for requests */\r\nconst INNERTUBE_CONTEXT = {\r\n client: {\r\n clientName: 'ANDROID',\r\n clientVersion: '20.10.38'\r\n }\r\n};\r\n\r\n/**\r\n * Fetches transcript lists from YouTube for given video IDs.\r\n * Handles consent cookies, retries on blocks, and extracts caption data.\r\n *\r\n * @example\r\n * ```typescript\r\n * const fetcher = new TranscriptListFetcher(httpClient, proxyConfig);\r\n * const transcriptList = await fetcher.fetchTranscriptList('dQw4w9WgXcQ');\r\n * ```\r\n */\r\nexport class TranscriptListFetcher {\r\n private httpClient: HttpClient;\r\n private proxyConfig: ProxyConfig | null;\r\n\r\n /**\r\n * Creates a new TranscriptListFetcher instance.\r\n *\r\n * @param {HttpClient} httpClient - The HTTP client to use for requests\r\n * @param {ProxyConfig | null} proxyConfig - Optional proxy configuration\r\n */\r\n constructor(httpClient: HttpClient, proxyConfig: ProxyConfig | null) {\r\n this.httpClient = httpClient;\r\n this.proxyConfig = proxyConfig;\r\n }\r\n\r\n /**\r\n * Fetches the list of available transcripts for a video.\r\n *\r\n * @param {string} videoId - The YouTube video ID\r\n * @returns {Promise<TranscriptList>} The transcript list\r\n * @throws {RequestBlocked} If requests are blocked and retries exhausted\r\n * @throws {IpBlocked} If IP is blocked by YouTube\r\n * @throws {YouTubeDataUnparsable} If YouTube data cannot be parsed\r\n * @throws {TranscriptsDisabled} If transcripts are disabled for the video\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcriptList = await fetcher.fetchTranscriptList('dQw4w9WgXcQ');\r\n * const transcript = transcriptList.findTranscript(['en']);\r\n * ```\r\n */\r\n async fetchTranscriptList(videoId: string): Promise<TranscriptList> {\r\n const captionsJson = await this.fetchCaptionsJsonWithRetry(videoId);\r\n return TranscriptList.buildFromCaptionsJson(this.httpClient, videoId, captionsJson);\r\n }\r\n\r\n /**\r\n * Fetches captions JSON with retry logic for blocked requests.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @param {number} [attemptNumber=0] - Current attempt number (for retry logic)\r\n * @returns {Promise<CaptionsJson>} The captions JSON data\r\n */\r\n private async fetchCaptionsJsonWithRetry(\r\n videoId: string,\r\n attemptNumber: number = 0\r\n ): Promise<CaptionsJson> {\r\n try {\r\n const htmlContent = await this.fetchVideoPageHtml(videoId);\r\n const apiKey = extractInnertubeApiKey(htmlContent, videoId);\r\n const innertubeData = await this.fetchInnertubePlayerData(videoId, apiKey);\r\n return extractCaptionsJson(innertubeData, videoId);\r\n } catch (error) {\r\n if (error instanceof RequestBlocked) {\r\n return this.handleBlockedRequest(error, videoId, attemptNumber);\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Handles blocked requests with retry logic based on proxy configuration.\r\n *\r\n * @private\r\n * @param {RequestBlocked} error - The blocked request error\r\n * @param {string} videoId - The video ID\r\n * @param {number} attemptNumber - Current attempt number\r\n * @returns {Promise<CaptionsJson>} The captions JSON data from retry\r\n * @throws {RequestBlocked} If retries are exhausted\r\n */\r\n private async handleBlockedRequest(\r\n error: RequestBlocked,\r\n videoId: string,\r\n attemptNumber: number\r\n ): Promise<CaptionsJson> {\r\n const maxRetries = this.proxyConfig?.retriesWhenBlocked || 0;\r\n\r\n if (attemptNumber + 1 < maxRetries) {\r\n return this.fetchCaptionsJsonWithRetry(videoId, attemptNumber + 1);\r\n }\r\n\r\n throw error.withProxyConfig(this.proxyConfig);\r\n }\r\n\r\n /**\r\n * Fetches the HTML content of a video's watch page, handling consent cookies.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @returns {Promise<string>} The HTML content\r\n * @throws {FailedToCreateConsentCookie} If consent cookie creation fails\r\n */\r\n private async fetchVideoPageHtml(videoId: string): Promise<string> {\r\n let htmlContent = await this.fetchAndDecodeHtml(videoId);\r\n\r\n // Handle YouTube consent cookie requirement\r\n if (this.isConsentPageDetected(htmlContent)) {\r\n this.createConsentCookie(htmlContent, videoId);\r\n htmlContent = await this.fetchAndDecodeHtml(videoId);\r\n\r\n if (this.isConsentPageDetected(htmlContent)) {\r\n throw new FailedToCreateConsentCookie(videoId);\r\n }\r\n }\r\n\r\n return htmlContent;\r\n }\r\n\r\n /**\r\n * Checks if the HTML content is a consent page.\r\n *\r\n * @private\r\n * @param {string} htmlContent - The HTML content to check\r\n * @returns {boolean} True if consent page detected\r\n */\r\n private isConsentPageDetected(htmlContent: string): boolean {\r\n return htmlContent.includes('action=\"https://consent.youtube.com/s\"');\r\n }\r\n\r\n /**\r\n * Fetches HTML from YouTube watch page and decodes HTML entities.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @returns {Promise<string>} The decoded HTML content\r\n */\r\n private async fetchAndDecodeHtml(videoId: string): Promise<string> {\r\n const url = this.buildWatchUrl(videoId);\r\n const response = await this.httpClient.get(url);\r\n handleHttpErrors(response, videoId);\r\n const rawHtml = await response.text();\r\n return decode(rawHtml);\r\n }\r\n\r\n /**\r\n * Builds the YouTube watch URL for a video ID.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @returns {string} The watch URL\r\n */\r\n private buildWatchUrl(videoId: string): string {\r\n return YOUTUBE_WATCH_URL.replace('{video_id}', videoId);\r\n }\r\n\r\n /**\r\n * Creates a consent cookie from the HTML content.\r\n * Note: This is a placeholder - cookie handling should be implemented in the HTTP client.\r\n *\r\n * @private\r\n * @param {string} htmlContent - The HTML content containing consent form\r\n * @param {string} videoId - The video ID\r\n * @throws {FailedToCreateConsentCookie} If consent value cannot be extracted\r\n */\r\n private createConsentCookie(htmlContent: string, videoId: string): void {\r\n const consentValuePattern = /name=\"v\" value=\"(.*?)\"/;\r\n const match = htmlContent.match(consentValuePattern);\r\n\r\n if (!match) {\r\n throw new FailedToCreateConsentCookie(videoId);\r\n }\r\n\r\n // TODO: Cookie handling would need to be implemented in the HTTP client\r\n // This is a placeholder for the cookie setting logic\r\n }\r\n\r\n /**\r\n * Fetches player data from YouTube's InnerTube API.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @param {string} apiKey - The InnerTube API key\r\n * @returns {Promise<InnerTubeData>} The InnerTube player data\r\n */\r\n private async fetchInnertubePlayerData(videoId: string, apiKey: string): Promise<InnerTubeData> {\r\n const url = this.buildInnertubeApiUrl(apiKey);\r\n const requestBody = this.buildInnertubeRequestBody(videoId);\r\n\r\n const response = await this.httpClient.post(url, {\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(requestBody)\r\n });\r\n\r\n handleHttpErrors(response, videoId);\r\n return (await response.json()) as InnerTubeData;\r\n }\r\n\r\n /**\r\n * Builds the InnerTube API URL with the provided API key.\r\n *\r\n * @private\r\n * @param {string} apiKey - The API key\r\n * @returns {string} The complete API URL\r\n */\r\n private buildInnertubeApiUrl(apiKey: string): string {\r\n return INNERTUBE_API_URL.replace('{api_key}', apiKey);\r\n }\r\n\r\n /**\r\n * Builds the request body for InnerTube API calls.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @returns {object} The request body\r\n */\r\n private buildInnertubeRequestBody(videoId: string): object {\r\n return {\r\n context: INNERTUBE_CONTEXT,\r\n videoId: videoId\r\n };\r\n }\r\n}\r\n","var e=/* @__PURE__ */(e=>(e.RESET=\"reset\",e.BLACK=\"black\",e.RED=\"red\",e.GREEN=\"green\",e.YELLOW=\"yellow\",e.BLUE=\"blue\",e.MAGENTA=\"magenta\",e.CYAN=\"cyan\",e.WHITE=\"white\",e.GRAY=\"gray\",e.BRIGHT_RED=\"brightRed\",e.BRIGHT_GREEN=\"brightGreen\",e.BRIGHT_YELLOW=\"brightYellow\",e.BRIGHT_BLUE=\"brightBlue\",e.BRIGHT_MAGENTA=\"brightMagenta\",e.BRIGHT_CYAN=\"brightCyan\",e.BRIGHT_WHITE=\"brightWhite\",e.BG_RED=\"bgRed\",e.BG_GREEN=\"bgGreen\",e.BG_YELLOW=\"bgYellow\",e.BG_BLUE=\"bgBlue\",e.BG_MAGENTA=\"bgMagenta\",e.BG_CYAN=\"bgCyan\",e.BG_WHITE=\"bgWhite\",e.BG_GRAY=\"bgGray\",e.BG_BLACK=\"bgBlack\",e.BG_BRIGHT_RED=\"bgBrightRed\",e.BG_BRIGHT_GREEN=\"bgBrightGreen\",e.BG_BRIGHT_YELLOW=\"bgBrightYellow\",e.BG_BRIGHT_BLUE=\"bgBrightBlue\",e.BG_BRIGHT_MAGENTA=\"bgBrightMagenta\",e.BG_BRIGHT_CYAN=\"bgBrightCyan\",e.BG_BRIGHT_WHITE=\"bgBrightWhite\",e))(e||{});const t={reset:[0,\"000000\"],black:[30,\"1f2937\"],red:[31,\"dc2626\"],green:[32,\"2d6a4f\"],yellow:[33,\"92400e\"],blue:[34,\"1a56db\"],magenta:[35,\"6d28d9\"],cyan:[36,\"0e7490\"],white:[37,\"374151\"],gray:[90,\"6b7280\"],brightRed:[91,\"ef4444\"],brightGreen:[92,\"059669\"],brightYellow:[93,\"d97706\"],brightBlue:[94,\"3b82f6\"],brightMagenta:[95,\"8b5cf6\"],brightCyan:[96,\"06b6d4\"],brightWhite:[97,\"f9fafb\"],bgBlack:[40,\"111827\"],bgRed:[41,\"fca5a5\"],bgGreen:[42,\"a7f3d0\"],bgYellow:[43,\"fde68a\"],bgBlue:[44,\"bfdbfe\"],bgMagenta:[45,\"ddd6fe\"],bgCyan:[46,\"a5f3fc\"],bgWhite:[47,\"f9fafb\"],bgGray:[100,\"d1d5db\"],bgBrightRed:[101,\"fee2e2\"],bgBrightGreen:[102,\"d1fae5\"],bgBrightYellow:[103,\"fef3c7\"],bgBrightBlue:[104,\"dbeafe\"],bgBrightMagenta:[105,\"ede9fe\"],bgBrightCyan:[106,\"cffafe\"],bgBrightWhite:[107,\"ffffff\"]};function r(e=\"ansi\"){const r={};for(const[n,[o,i]]of Object.entries(t))r[n]=\"html\"===e?\"reset\"===n?\"</span>\":`<span style=\"color:#${i}\">`:\"\u001b[\"+o+\"m\";return r}function n(e,t=\"ansi\"){const n=r(t);return\"string\"==typeof e?n.yellow:\"number\"==typeof e?n.cyan:\"boolean\"==typeof e?n.magenta:\"function\"==typeof e?n.red:null===e?n.gray:Array.isArray(e)?n.blue:\"object\"==typeof e?n.green:n.white}function o(e){return\"string\"==typeof e?'\"\"':\"number\"==typeof e?\"number\":\"boolean\"==typeof e?\"bool\":\"function\"==typeof e?\"function\":null===e?\"null\":Array.isArray(e)?e.length?\"[\"+o(e[0])+\"]\":\"[]\":\"object\"==typeof e?\"{...}\":typeof e}function i(e,t=0,l=\"ansi\"){const g=r(l),a=\"html\"===l,s=\" \".repeat(t);if(\"object\"!=typeof e||null===e){return n(e,l)+o(e)+g.reset}if(Array.isArray(e)){if(a){let r=[];e.length&&(r=e.every(t=>typeof t==typeof e[0])?[i(e[0],t+1,l)]:e.map(e=>i(e,t+1,l)));return`<details open><summary style=\"cursor:pointer;display:inline\">${`${g.blue}[${g.reset} ${e.length} × ${o(e[0]??void 0)} ${g.blue}]${g.reset}`}</summary>${r.map(e=>`<div style=\"margin-left:1.5em\">${e}</div>`).join(\"\")}</details>`}let r=g.blue+\"[\"+g.reset;return e.length&&(r+=\"\\n\"),e.every(t=>typeof t==typeof e[0])?r+=s+\" \"+i(e[0],t+1,l)+\",\\n\":e.forEach((n,o)=>{r+=s+\" \"+i(n,t+1,l),o<e.length-1&&(r+=\",\"),r+=\"\\n\"}),r+=s+g.blue+\"]\"+g.reset,r}const b=Object.keys(e);if(a){const r=b.slice(0,4).join(\", \")+(b.length>4?\"…\":\"\");return`<details open><summary style=\"cursor:pointer\">${`${g.green}{${g.reset} ${r} ${g.green}}${g.reset}`}</summary>${b.map(r=>{const a=e[r],s=n(a,l);return\"object\"==typeof a&&null!==a?`<div style=\"margin-left:1.5em\">${s}${r}${g.reset}: ${i(a,t+1,l)}</div>`:`<div style=\"margin-left:1.5em\">${s}${r}: ${o(a)}${g.reset}</div>`}).join(\"\")}</details>`}let f=g.green+\"{\"+g.reset;return b.length&&(f+=\"\\n\"),b.forEach((r,a)=>{const y=e[r],c=n(y,l);f+=s+\" \",f+=\"object\"==typeof y&&null!==y?c+r+g.reset+\": \"+i(y,t+1,l):c+r+\": \"+o(y)+g.reset,a<b.length-1&&(f+=\",\"),f+=\"\\n\"}),f+=s+g.green+\"}\"+g.reset,f}function l(e=\"\",t={}){let{color:n,style:o=\"color:rgb(54, 165, 220); font-size: 10pt;\",hideInProduction:l,startSpinner:g=!1,stopSpinner:a=!1}=t;const s=r();void 0===l&&(l=\"undefined\"!=typeof window&&window?.location.hostname.includes(\"localhost\")),\"object\"==typeof e&&(e=i(e)+\"\\n\\n\"+JSON.stringify(e,null,2)),Array.isArray(n)&&1==n.length&&(n=n[0]),n&&\"undefined\"!=typeof process&&(\"string\"==typeof e&&e.includes(\"%c\")&&Array.isArray(n)?e=e.replace(/%c/g,(e,t)=>s[n[t]]||\"\"):n&&\"string\"==typeof n&&(e=(s[n]||\"\")+e+s.reset));var b=0;return g?globalThis.interval=setInterval(()=>{process.stdout.write((Array.isArray(n)?s[n[0]]:s[n]||\"\")+\"\\r\"+\"⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏\".split(\"\")[b=++b%10]+\" \"+e+s.reset)},50):a?(clearInterval(globalThis.interval),process.stdout.write(\"\\r\"+(e||\" \")+\" \".repeat(\"string\"==typeof e?e.length+20:40)+\"\\n\")):\"string\"==typeof o?(1==o.split(\" \").length||n?o=`color: ${n||o}; font-size: 11pt;`:o.match(/^#[0-9a-fA-F]{6}$/)&&(o=`color: ${o}; font-size: 11pt;`),l?console.debug((o?\"%c\":\"\")+(e||\"\"),o):console.log((o?\"%c\":\"\")+(e||\"\"),o)):\"object\"==typeof o&&console.log(e,...o),!0}export{e as ColorName,r as getColors,l as log,i as printJSONStructure};\n//# sourceMappingURL=log.es.js.map\n","import{printJSONStructure as e,log as t}from\"./log.es.js\";const n=async(e,t)=>{let n;return async function(...o){clearTimeout(n),n=setTimeout(async()=>{clearTimeout(n),await e(...o)},t)}},o=e=>new Promise(t=>setTimeout(t,1e3*e||0)),r=(e,t)=>{let n=e=>t?.startsWith(e)||!1,o=e,r=t;return t?.startsWith(\"http:\")||t?.startsWith(\"https:\")?o=\"\":n(\"/\")||o.endsWith(\"/\")?n(\"/\")&&o.endsWith(\"/\")&&(r=t.slice(1)):r=\"/\"+t,{baseURL:o,path:r}};function s(e){if(\"undefined\"==typeof document)return;let t,n=document.getElementById(\"alert-overlay\");if(!n){n=document.body.appendChild(document.createElement(\"div\")),n.id=\"alert-overlay\",n.setAttribute(\"style\",\"position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center\"),n.innerHTML='<div id=\"alert-box\" style=\"background:#fff;padding:1.5em 2em;border-radius:8px;box-shadow:0 2px 16px #0003;min-width:320px;max-width:90vw;max-height:80vh;position:relative;display:flex;flex-direction:column;\">\\n <button id=\"close-alert\" style=\"position:absolute;top:12px;right:20px;font-size:1.5em;background:none;border:none;cursor:pointer;color:black;\">×</button>\\n <div id=\"alert-list\" style=\"overflow:auto;flex:1;font-family:monospace;font-size:13px;\"></div>\\n </div>',n.addEventListener(\"click\",e=>e.target==n&&n.remove());const e=document.getElementById(\"close-alert\");e&&(e.onclick=()=>n.remove())}t=document.getElementById(\"alert-list\"),t.innerHTML+=`<div style=\"border-bottom:1px solid #e5e7eb;margin:0.5em 0;padding-bottom:0.5em\">${e}</div>`}function i(e){return e.replace(/&/g,\"&\").replace(/</g,\"<\").replace(/>/g,\">\")}function a(){\"undefined\"!=typeof document&&document.addEventListener(\"keydown\",t=>{const n=window.grab;if(n&&n.log&&\"i\"===t.key&&t.ctrlKey&&t.altKey){let t=\"\";for(const o of n.log){const n=new Date(o.lastFetchTime).toLocaleString(),r=e(o.request,0,\"html\"),s=e(o.response,0,\"html\"),a=i(JSON.stringify(o.response,null,2));t+=`\\n <details open style=\"margin-bottom:0.75em\">\\n <summary style=\"cursor:pointer;font-weight:bold;padding:4px 0;list-style:none;display:flex;justify-content:space-between\">\\n <span style=\"color:#1a56db\">${i(o.path)}</span>\\n <span style=\"color:#6b7280;font-weight:normal;margin-left:1em\">${n}</span>\\n </summary>\\n <div style=\"padding-left:1em;margin-top:0.5em\">\\n <details style=\"margin-bottom:0.4em\">\\n <summary style=\"cursor:pointer;color:#6b7280;font-size:0.9em\">Request</summary>\\n <div style=\"padding:0.4em 0 0 1em\">${r}</div>\\n </details>\\n <details open style=\"margin-bottom:0.4em\">\\n <summary style=\"cursor:pointer;color:#6b7280;font-size:0.9em\">Response (structure)</summary>\\n <div style=\"padding:0.4em 0 0 1em\">${s}</div>\\n </details>\\n <details style=\"margin-bottom:0.4em\">\\n <summary style=\"cursor:pointer;color:#6b7280;font-size:0.9em\">Response (data)</summary>\\n <pre style=\"margin:0.4em 0 0 1em;padding:0.5em;background:#f9fafb;border:1px solid #e5e7eb;border-radius:4px;overflow:auto;max-height:300px;font-size:12px\">${a}</pre>\\n </details>\\n </div>\\n </details>`}s(t||\"<em>No requests logged yet.</em>\")}})}function l(o){return async function i(a,l){const c=function(e){return{...\"undefined\"!=typeof window?window?.grab?.defaults:globalThis?.grab?.defaults||{},...e}}(l);let{headers:d,response:u,method:f=(c.post?\"POST\":c.put?\"PUT\":c.patch?\"PATCH\":\"GET\"),cache:p,timeout:m=30,baseURL:y=\"undefined\"!=typeof process&&process.env.SERVER_API_URL||\"/api/\",cancelOngoingIfNew:g,cancelNewIfOngoing:b,rateLimit:w,debug:h,infiniteScroll:v,logger:T=t,onRequest:x,onResponse:L,onError:E,onStream:A,unzip:S,dom:O,body:R,post:P,put:k,patch:$,...j}=c;const q=r(y,a);y=q.baseURL,a=q.path;const F=function(e){const t=\"function\"==typeof e?e:null;return{response:!e||t?{}:e,resFunction:t}}(u);let N=F.response,D=F.resFunction;const z=\"undefined\"!=typeof window?window.grab:globalThis.grab,I=z?.log||[];D?N=D({...N,isLoading:!0}):\"object\"==typeof N&&(N.isLoading=!0);try{const r=await async function(e,t,o,r){const{debounce:s=0,repeat:i=0,repeatEvery:a=null,setDefaults:l=!1}=o;if(s>0){const i=await n(async()=>{await r(e,{...t,debounce:0})},1e3*s);return await i(),o.response||{}}if(i>1){for(let n=0;n<i;n++)await r(e,{...t,repeat:0});return o.response||{}}if(a)return setInterval(async()=>{await r(e,{...t,repeat:0,repeatEvery:null})},1e3*a),o.response||{};if(l){const e=\"undefined\"!=typeof window?window.grab:globalThis.grab;return e&&(e.defaults={...t,setDefaults:void 0}),o.response||{}}return null}(a,l||{},c,i);if(r)return r;!function(e,t,n,o){if(\"undefined\"==typeof window)return;const{regrabOnStale:r,regrabOnFocus:s,regrabOnNetwork:i,cache:a,cacheForTime:l=60}=n,c=async()=>await o(e,{...t,cache:!1});r&&a&&setTimeout(c,1e3*l),i&&window.addEventListener(\"online\",c),s&&(window.addEventListener(\"focus\",c),document.addEventListener(\"visibilitychange\",async()=>{\"visible\"===document.visibilityState&&await c()}))}(a,l||{},c,i);let{params:s,priorRequest:u,response:E,paramsAsText:P}=function(e,t,n,o,r,s){const{cache:i,cacheForTime:a,infiniteScroll:l}=n,[c,d]=l||[],u=JSON.stringify(c?{...t,[c]:void 0}:t);let f=s.find(t=>t.request===u&&t.path===e);if(c){let e=(f?.currentPage||0)+1||t?.[c]||1;f?f.currentPage=e:(o[d]=[],e=1),t={...t,[c]:e}}else{for(let e of Object.keys(o))o[e]=void 0;if(i&&f?.response&&(!a||f.lastFetchTime>Date.now()-1e3*a)){for(let e of Object.keys(f.response))o[e]=f.response[e];r&&(o=r(o))}}return{params:t,priorRequest:f,response:o,paramsAsText:u}}(a,j,c,N,D,I);if(j=s,N=E,function(e,n,o,r,s){if(\"undefined\"==typeof window||!o?.length)return;const[i,,a]=o;if(void 0===a)return;let l=\"string\"==typeof a?document.querySelector(a):a;l?(window.scrollListener&&\"function\"==typeof l.removeEventListener&&l.removeEventListener(\"scroll\",window.scrollListener),window.scrollListener=t=>{const o=t.target;localStorage.setItem(\"scroll\",JSON.stringify([o.scrollTop,o.scrollLeft,a])),o.scrollHeight-o.scrollTop<=o.clientHeight+200&&s(e,{...n,cache:!1,[i]:(r?.currentPage||0)+1})},l.addEventListener(\"scroll\",window.scrollListener)):t(\"paginateDOM not found\",{color:\"red\"})}(a,l,v,u,i),w>0&&u?.lastFetchTime>Date.now()-1e3*w)throw new Error(`Fetch rate limit exceeded for ${a}. Wait ${w}s between requests.`);if(u?.controller)if(g)u.controller.abort();else if(b)return{isLoading:!0};const k=new AbortController;let $=k.signal;g||\"function\"!=typeof AbortSignal.timeout||($=AbortSignal.timeout(1e3*m)),I.unshift({path:a,request:P,lastFetchTime:Date.now(),controller:k});let{fetchParams:q,paramsGETRequest:F}=function(e,t,n,o,r,s){const i=[\"POST\",\"PUT\",\"PATCH\"].includes(e),a={method:e,headers:{\"Content-Type\":\"application/json\",Accept:\"application/json\",...t},body:n||(i?JSON.stringify(o):null),redirect:\"follow\",cache:r?\"force-cache\":\"no-store\",signal:s};let l=\"\";return i||(l=(Object.keys(o).length?\"?\":\"\")+new URLSearchParams(o).toString()),{fetchParams:a,paramsGETRequest:l}}(f,d,R,j,!!p,$);if(\"function\"==typeof x){const e=x(a,N,j,q);Array.isArray(e)&&([a,N,j,q]=e)}const z=/* @__PURE__ */new Date,U=await o(y,a,F,q,j,A,S,O);if(D?N=D({...N,isLoading:void 0}):\"object\"==typeof N&&delete N.isLoading,\"function\"==typeof L){const e=L(a,N,j,q);Array.isArray(e)&&([a,N,j,q]=e)}const H=((Number(/* @__PURE__ */new Date)-Number(z))/1e3).toFixed(1);h&&T(`Path:${y+a+F}\\n${JSON.stringify(l,null,2)}\\nTime: ${H}s\\nResponse: ${e(U)}`);const[,W]=v||[];return N=function(e,t,n,o){if(\"object\"==typeof e&&null!==e){for(let n of Object.keys(e))t[n]=o===n&&Array.isArray(t[n])?[...t[n],...e[n]]:e[n];t.data=e}else n?t=n({data:e,...e}):\"object\"==typeof t&&(t.data=e);return t}(U,N,D,W),I[0]&&(I[0].response=N),D&&(N=D(N)),N}catch(U){if(\"function\"==typeof E&&E(U.message,y+a,j),c.retryAttempts&&c.retryAttempts>0)return await i(a,{...l,retryAttempts:--c.retryAttempts});!U.message.includes(\"signal\")&&h&&(T(`Error: ${U.message}\\nPath:${y+a}\\n`,{color:\"red\"}),\"undefined\"!=typeof document&&s(U.message)),N=N||{},N.error=U.message;const e=\"function\"==typeof u?u:null;return e?(N.data=e({isLoading:void 0,error:U.message}),N=N.data):delete N.isLoading,N}}}export{s as a,r as b,l as c,n as d,a as s,o as w};\n//# sourceMappingURL=core-BX1uvK6L.js.map\n","import{w as t,s as r,c as o}from\"./core-BX1uvK6L.js\";import{b as e,d as n,a}from\"./core-BX1uvK6L.js\";import{log as s}from\"./log.es.js\";async function i(t){const{extract:r}=await import(\"./archiver-web.es.js\"),o=await r({archiveBuffer:t}),e={};for(const n of o)e[n.path]=n.content;return e}async function c(t,r){const{parseHTML:o}=await import(\"./index-CLlAnStL.js\"),{document:e}=o(t);if(!r||!0===r)return e;const n=e.querySelector(r);return n?n.innerHTML??n.textContent:null}const l=o(async function(r,o,e,n,a,s,l,d){const p=\"undefined\"!=typeof window?window.grab:globalThis.grab,u=p?.mock?.[o],f=JSON.stringify(a);if(u&&(!u.method||u.method===n.method)&&(!u.params||f===JSON.stringify(u.params)))return await t(u.delay||0),\"function\"==typeof u.response?u.response(a):u.response;const w=await fetch(r+o+e,n).catch(t=>{throw new Error(t.message)});if(!w.ok)throw new Error(`HTTP error: ${w.status} ${w.statusText}`);if(s)return await s(w.body),null;const h=w.headers.get(\"content-type\")??\"\",g=!1!==l&&(h.includes(\"application/zip\")||h.includes(\"application/x-zip\")),m=!1!==d&&(\"string\"==typeof d||h.includes(\"text/html\"));if(g){const t=await w.arrayBuffer().catch(t=>{throw new Error(\"Error reading zip: \"+t)});return{data:await i(t)}}if(m){const t=await w.text().catch(t=>{throw new Error(\"Error reading html: \"+t)});return{data:await c(t,\"string\"!=typeof d||d)}}return await(h.includes(\"application/json\")?w.json():h.includes(\"application/pdf\")||h.includes(\"application/octet-stream\")?w.blob():h?w.text():w.json()).catch(t=>{throw new Error(\"Error parsing response: \"+t)})}),d=l;d.instance=(t={})=>(r,o={})=>l(r,{...t,...o}),d.log=[],d.mock={},d.defaults={},\"undefined\"!=typeof window?(window.log=s,window.grab=d,r(),document.addEventListener(\"DOMContentLoaded\",()=>{try{const t=localStorage.getItem(\"scroll\");if(!t)return;const[r,o,e]=JSON.parse(t);if(!r||!e)return;const n=document.querySelector(e);n&&(n.scrollTop=r,n.scrollLeft=o)}catch(t){console.warn(\"Failed to restore scroll position\",t)}})):\"undefined\"!=typeof globalThis&&(globalThis.log=s,globalThis.grab=d);export{e as buildUrl,n as debouncer,d as default,d as grab,s as log,r as setupDevTools,a as showAlert,t as wait};\n//# sourceMappingURL=grab-api.es.js.map\n","/**\r\n * @fileoverview HTTP client implementation using grab-url\r\n */\r\n\r\nimport grab from 'grab-url';\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\nimport { HttpClient, RequestsProxyConfigDict } from '../types';\r\n\r\n/**\r\n * Simple HTTP client implementation using grab-url with proxy support.\r\n * This client handles HTTP/HTTPS requests with configurable headers and proxy settings.\r\n *\r\n * @internal\r\n */\r\nexport class FetchHttpClient implements HttpClient {\r\n private requestHeaders: Record<string, string> = {};\r\n private proxyConfiguration: Partial<RequestsProxyConfigDict> = {};\r\n\r\n /**\r\n * Creates a new FetchHttpClient instance.\r\n * Sets default Accept-Language header to English.\r\n */\r\n constructor() {\r\n this.requestHeaders['Accept-Language'] = 'en-US';\r\n }\r\n\r\n /**\r\n * Sets a custom header for all requests.\r\n *\r\n * @param {string} headerName - The header name\r\n * @param {string} headerValue - The header value\r\n */\r\n setHeader(headerName: string, headerValue: string): void {\r\n this.requestHeaders[headerName] = headerValue;\r\n }\r\n\r\n /**\r\n * Configures proxy settings for all requests.\r\n *\r\n * @param {RequestsProxyConfigDict} proxies - Proxy configuration dictionary\r\n */\r\n setProxies(proxies: RequestsProxyConfigDict): void {\r\n this.proxyConfiguration = proxies;\r\n }\r\n\r\n /**\r\n * Performs an HTTP GET request.\r\n *\r\n * @param {string} url - The URL to request\r\n * @param {RequestInit} [options] - Additional request options\r\n * @returns {Promise<Response>} The HTTP response\r\n */\r\n async get(url: string, options?: RequestInit): Promise<Response> {\r\n const proxyAgent = this.getProxyAgentForUrl(url);\r\n return grab(url, {\r\n ...options,\r\n method: 'GET',\r\n headers: { ...this.requestHeaders, ...(options?.headers as Record<string, string>) },\r\n agent: proxyAgent\r\n } as any);\r\n }\r\n\r\n /**\r\n * Performs an HTTP POST request.\r\n *\r\n * @param {string} url - The URL to request\r\n * @param {RequestInit} [options] - Additional request options\r\n * @returns {Promise<Response>} The HTTP response\r\n */\r\n async post(url: string, options?: RequestInit): Promise<Response> {\r\n const proxyAgent = this.getProxyAgentForUrl(url);\r\n return grab(url, {\r\n ...options,\r\n method: 'POST',\r\n headers: { ...this.requestHeaders, ...(options?.headers as Record<string, string>) },\r\n agent: proxyAgent\r\n } as any);\r\n }\r\n\r\n /**\r\n * Gets the appropriate proxy agent for a given URL.\r\n *\r\n * @private\r\n * @param {string} url - The URL being requested\r\n * @returns {any} The proxy agent or undefined if no proxy is configured\r\n */\r\n private getProxyAgentForUrl(url: string): any {\r\n if (Object.keys(this.proxyConfiguration).length === 0) {\r\n return undefined;\r\n }\r\n\r\n const proxyUrl = url.startsWith('https://')\r\n ? this.proxyConfiguration.https\r\n : this.proxyConfiguration.http;\r\n\r\n if (!proxyUrl) {\r\n return undefined;\r\n }\r\n\r\n return new HttpsProxyAgent(proxyUrl);\r\n }\r\n}\r\n","/**\r\n * @fileoverview Main API class for the YouTube Transcript API\r\n */\r\n\r\nimport { ProxyConfig } from './proxies';\r\nimport { FetchedTranscript, TranscriptList } from './models';\r\nimport { TranscriptListFetcher } from './fetchers/transcript-list-fetcher';\r\nimport { HttpClient } from './types';\r\nimport { FetchHttpClient } from './http/fetch-http-client';\r\n\r\n/**\r\n * Main API class for retrieving YouTube transcripts.\r\n * This is the primary entry point for the library.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Basic usage\r\n * const api = new YouTubeTranscriptApi();\r\n * const transcript = await api.fetchTranscript('video_id');\r\n *\r\n * // With language preference\r\n * const transcript = await api.fetchTranscript('video_id', { languages: ['de', 'en'] });\r\n *\r\n * // With proxy\r\n * import { GenericProxyConfig } from 'youtube-transcript-api';\r\n * const api = new YouTubeTranscriptApi({\r\n * proxyConfig: new GenericProxyConfig({\r\n * httpUrl: 'http://user:pass@proxy.example.com:8080'\r\n * })\r\n * });\r\n * ```\r\n */\r\nexport class YouTubeTranscriptApi {\r\n private transcriptListFetcher: TranscriptListFetcher;\r\n\r\n /**\r\n * Creates a new YouTubeTranscriptApi instance.\r\n *\r\n * Note on thread-safety: As this class initializes an HTTP client,\r\n * it is not thread-safe. Make sure to initialize an instance per\r\n * thread if used in a multi-threading scenario!\r\n *\r\n * @param {Object} [options] - Configuration options\r\n * @param {ProxyConfig} [options.proxyConfig] - An optional ProxyConfig object defining proxies\r\n * used for all network requests. This can be used to work around your IP being blocked\r\n * by YouTube, as described in the \"Working around IP bans\" section of the README.\r\n * @param {HttpClient} [options.httpClient] - You can optionally pass in a custom HTTP client\r\n * if you want to share state between different instances of YouTubeTranscriptApi or\r\n * customize request behavior.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Basic usage\r\n * const api = new YouTubeTranscriptApi();\r\n *\r\n * // With Webshare proxy\r\n * import { WebshareProxyConfig } from 'youtube-transcript-api';\r\n * const api = new YouTubeTranscriptApi({\r\n * proxyConfig: new WebshareProxyConfig({\r\n * proxyUsername: 'your-username',\r\n * proxyPassword: 'your-password',\r\n * filterIpLocations: ['us', 'de']\r\n * })\r\n * });\r\n *\r\n * // With generic proxy\r\n * import { GenericProxyConfig } from 'youtube-transcript-api';\r\n * const api = new YouTubeTranscriptApi({\r\n * proxyConfig: new GenericProxyConfig({\r\n * httpUrl: 'http://user:pass@proxy.example.com:8080',\r\n * httpsUrl: 'https://user:pass@proxy.example.com:8080'\r\n * })\r\n * });\r\n * ```\r\n */\r\n constructor(options?: { proxyConfig?: ProxyConfig; httpClient?: HttpClient }) {\r\n const httpClient = this.initializeHttpClient(options);\r\n this.configureHttpClientWithProxy(httpClient, options?.proxyConfig);\r\n this.transcriptListFetcher = new TranscriptListFetcher(httpClient, options?.proxyConfig || null);\r\n }\r\n\r\n /**\r\n * Initializes the HTTP client from options or creates a default one.\r\n *\r\n * @private\r\n * @param {Object} [options] - Configuration options\r\n * @returns {HttpClient} The initialized HTTP client\r\n */\r\n private initializeHttpClient(options?: { httpClient?: HttpClient }): HttpClient {\r\n return options?.httpClient || new FetchHttpClient();\r\n }\r\n\r\n /**\r\n * Configures the HTTP client with proxy settings if provided.\r\n *\r\n * @private\r\n * @param {HttpClient} httpClient - The HTTP client to configure\r\n * @param {ProxyConfig} [proxyConfig] - Optional proxy configuration\r\n */\r\n private configureHttpClientWithProxy(httpClient: HttpClient, proxyConfig?: ProxyConfig): void {\r\n if (!proxyConfig || !(httpClient instanceof FetchHttpClient)) {\r\n return;\r\n }\r\n\r\n const proxyDictionary = proxyConfig.toRequestsDict();\r\n httpClient.setProxies(proxyDictionary);\r\n\r\n if (proxyConfig.preventKeepingConnectionsAlive) {\r\n httpClient.setHeader('Connection', 'close');\r\n }\r\n\r\n // Note: Retry logic for 429 status codes with configured retries\r\n // would need to be implemented in the HTTP client or fetcher\r\n }\r\n\r\n /**\r\n * Retrieves the transcript for a single video.\r\n * This is a shortcut for calling:\r\n * `api.listTranscripts(videoId).then(list => list.findTranscript(languages)).then(t => t.fetch())`\r\n *\r\n * @param {string} videoId - The ID of the video you want to retrieve the transcript for.\r\n * Make sure that this is the actual ID, NOT the full URL to the video!\r\n * @param {Object} [options] - Fetch options\r\n * @param {string[]} [options.languages=['en']] - A list of language codes in descending priority.\r\n * For example, if this is set to ['de', 'en'] it will first try to fetch the german\r\n * transcript (de) and then fetch the english transcript (en) if it fails to do so.\r\n * @param {boolean} [options.preserveFormatting=false] - Whether to keep select HTML text formatting\r\n * @returns {Promise<FetchedTranscript>} The fetched transcript\r\n *\r\n * @example\r\n * ```typescript\r\n * const api = new YouTubeTranscriptApi();\r\n *\r\n * // Fetch English transcript\r\n * const transcript = await api.fetchTranscript('dQw4w9WgXcQ');\r\n *\r\n * // Fetch with language preference\r\n * const transcript = await api.fetchTranscript('dQw4w9WgXcQ', {\r\n * languages: ['de', 'en']\r\n * });\r\n *\r\n * // Preserve HTML formatting\r\n * const transcript = await api.fetchTranscript('dQw4w9WgXcQ', {\r\n * preserveFormatting: true\r\n * });\r\n *\r\n * // Iterate over snippets\r\n * for (const snippet of transcript) {\r\n * console.log(`${snippet.start}s: ${snippet.text}`);\r\n * }\r\n * ```\r\n */\r\n async fetchTranscript(\r\n videoId: string,\r\n options?: {\r\n languages?: string[];\r\n preserveFormatting?: boolean;\r\n }\r\n ): Promise<FetchedTranscript> {\r\n const preferredLanguages = options?.languages || ['en'];\r\n const preserveFormatting = options?.preserveFormatting || false;\r\n\r\n const transcriptList = await this.listTranscripts(videoId);\r\n const transcript = transcriptList.findTranscript(preferredLanguages);\r\n return transcript.fetch(preserveFormatting);\r\n }\r\n\r\n /**\r\n * Retrieves the list of transcripts which are available for a given video.\r\n * It returns a TranscriptList object which is iterable and provides methods to\r\n * filter the list of transcripts for specific languages.\r\n *\r\n * While iterating over the TranscriptList, the individual transcripts are\r\n * represented by Transcript objects, which provide metadata and can either\r\n * be fetched by calling transcript.fetch() or translated by calling\r\n * transcript.translate('en').\r\n *\r\n * @param {string} videoId - The ID of the video you want to retrieve the transcript for.\r\n * Make sure that this is the actual ID, NOT the full URL to the video!\r\n * @returns {Promise<TranscriptList>} A list of available transcripts\r\n *\r\n * @example\r\n * ```typescript\r\n * const api = new YouTubeTranscriptApi();\r\n *\r\n * // Retrieve available transcripts\r\n * const transcriptList = await api.listTranscripts('video_id');\r\n *\r\n * // Iterate over all available transcripts\r\n * for (const transcript of transcriptList) {\r\n * console.log(\r\n * transcript.videoId,\r\n * transcript.language,\r\n * transcript.languageCode,\r\n * transcript.isGenerated,\r\n * transcript.isTranslatable,\r\n * transcript.translationLanguages\r\n * );\r\n *\r\n * // Fetch the actual transcript data\r\n * const fetched = await transcript.fetch();\r\n * console.log(fetched);\r\n *\r\n * // Translate the transcript\r\n * if (transcript.isTranslatable) {\r\n * const translated = transcript.translate('de');\r\n * const fetchedTranslated = await translated.fetch();\r\n * console.log(fetchedTranslated);\r\n * }\r\n * }\r\n *\r\n * // Filter for specific language\r\n * const transcript = transcriptList.findTranscript(['de', 'en']);\r\n *\r\n * // Filter for manually created transcripts\r\n * const manual = transcriptList.findManuallyCreatedTranscript(['de', 'en']);\r\n *\r\n * // Filter for automatically generated transcripts\r\n * const generated = transcriptList.findGeneratedTranscript(['de', 'en']);\r\n * ```\r\n */\r\n async listTranscripts(videoId: string): Promise<TranscriptList> {\r\n return this.transcriptListFetcher.fetchTranscriptList(videoId);\r\n }\r\n\r\n /**\r\n * Alias for fetchTranscript() for backward compatibility.\r\n *\r\n * @deprecated Use fetchTranscript() instead\r\n * @param {string} videoId - The video ID\r\n * @param {Object} [options] - Fetch options\r\n * @returns {Promise<FetchedTranscript>} The fetched transcript\r\n */\r\n async fetch(\r\n videoId: string,\r\n options?: {\r\n languages?: string[];\r\n preserveFormatting?: boolean;\r\n }\r\n ): Promise<FetchedTranscript> {\r\n return this.fetchTranscript(videoId, options);\r\n }\r\n\r\n /**\r\n * Alias for listTranscripts() for backward compatibility.\r\n *\r\n * @deprecated Use listTranscripts() instead\r\n * @param {string} videoId - The video ID\r\n * @returns {Promise<TranscriptList>} A list of available transcripts\r\n */\r\n async list(videoId: string): Promise<TranscriptList> {\r\n return this.listTranscripts(videoId);\r\n }\r\n}\r\n","/**\r\n * @fileoverview Transcript timing utilities: encode/decode run-length compressed\r\n * playback speeds and interpolate timestamps from character offsets.\r\n */\r\n\r\nimport { FetchedTranscript } from '../models';\r\n\r\n/**\r\n * Encodes speech speed from a fetched transcript into a compact run-length string.\r\n * Optionally prepends a YouTube embed iframe with data-timestamps for player sync.\r\n * @param transcript - A FetchedTranscript returned by fetchTranscript()\r\n * @param addPlayer - If true, prepends an iframe embed with data-timestamps attribute\r\n * @returns html content, word count, run-length encoded speed string, and raw timestamps\r\n */\r\nexport function encodeTranscriptSpeeds(\r\n transcript: FetchedTranscript,\r\n addPlayer = false\r\n): {\r\n html: string;\r\n word_count: number;\r\n speeds: string;\r\n} {\r\n let charCount = 0;\r\n const timestamps: [number, number][] = [];\r\n const textParts: string[] = [];\r\n\r\n for (const snippet of transcript.snippets) {\r\n textParts.push(snippet.text);\r\n charCount += snippet.text.length;\r\n if (snippet.start > 0) {\r\n timestamps.push([charCount, snippet.start]);\r\n }\r\n }\r\n\r\n const content = textParts.join(' ').replace(/\\s+/g, ' ');\r\n const word_count = content.split(/\\s+/).filter(Boolean).length;\r\n\r\n const speedValues = timestamps.map(([char, time]) => Math.floor(char / time) - 10);\r\n if (speedValues.length === 0) {\r\n return { html: content, word_count, speeds: '' };\r\n }\r\n\r\n const compressed: number[] = [];\r\n const compressedCount: number[] = [];\r\n let currentNum = speedValues[0];\r\n let count = 1;\r\n\r\n for (let i = 1; i < speedValues.length; i++) {\r\n if (speedValues[i] === currentNum) {\r\n count++;\r\n } else {\r\n compressed.push(currentNum);\r\n compressedCount.push(count);\r\n currentNum = speedValues[i];\r\n count = 1;\r\n }\r\n }\r\n compressed.push(currentNum);\r\n compressedCount.push(count);\r\n\r\n const speeds = compressed.map((val, i) => `${val}x${compressedCount[i]}`).join(',');\r\n\r\n const html = addPlayer\r\n ? `<iframe width=\"100%\" height=\"315px\" data-timestamps=\"${speeds}\" ` +\r\n `src=\"https://www.youtube.com/embed/${transcript.videoId}\" frameborder=\"0\" ` +\r\n `allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; ` +\r\n `gyroscope; picture-in-picture\" allowfullscreen></iframe>${content}`\r\n : content;\r\n\r\n return { html, word_count, speeds };\r\n}\r\n\r\n/**\r\n * Given a character index in the joined transcript text, returns the interpolated\r\n * video timestamp in seconds. Uses the nearest snippet boundaries to interpolate.\r\n */\r\nexport function getTimestampAtChar(transcript: FetchedTranscript, charIndex: number): number {\r\n let charCount = 0;\r\n const points: [number, number][] = [[0, 0]]; // [cumulativeChars, seconds]\r\n\r\n for (const snippet of transcript.snippets) {\r\n charCount += snippet.text.length + 1; // +1 for the join space\r\n points.push([charCount, snippet.start]);\r\n }\r\n\r\n if (charIndex <= 0) return 0;\r\n if (charIndex >= points[points.length - 1][0]) return points[points.length - 1][1];\r\n\r\n for (let i = 1; i < points.length; i++) {\r\n if (points[i][0] >= charIndex) {\r\n const [c0, t0] = points[i - 1];\r\n const [c1, t1] = points[i];\r\n const ratio = (charIndex - c0) / (c1 - c0);\r\n return t0 + ratio * (t1 - t0);\r\n }\r\n }\r\n\r\n return points[points.length - 1][1];\r\n}\r\n\r\n/**\r\n * Decompresses a speeds string produced by encodeTranscriptSpeeds back into a flat array.\r\n * Format: \"12x3,8x7,15x1\" → [12,12,12, 8,8,8,8,8,8,8, 15]\r\n */\r\nexport function decompressTimestampsArray(speeds: string): number[] {\r\n const decompressed: number[] = [];\r\n for (const part of speeds.split(',')) {\r\n const [num, count] = part.split('x');\r\n decompressed.push(...Array(parseInt(count)).fill(parseInt(num)));\r\n }\r\n return decompressed;\r\n}\r\n","/**\r\n * @fileoverview Proxy configuration classes for the YouTube Transcript API\r\n */\r\n\r\nimport { RequestsProxyConfigDict } from '../types';\r\n\r\n/**\r\n * Exception for invalid proxy configurations\r\n */\r\nexport class InvalidProxyConfig extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'InvalidProxyConfig';\r\n Object.setPrototypeOf(this, InvalidProxyConfig.prototype);\r\n }\r\n}\r\n\r\n/**\r\n * Base class for all proxy configurations.\r\n * Any proxy config can be used as long as it can be converted to a RequestsProxyConfigDict.\r\n */\r\nexport abstract class ProxyConfig {\r\n /**\r\n * Converts this proxy config to a dictionary that can be used by HTTP clients.\r\n * @returns {RequestsProxyConfigDict} The proxy configuration dictionary\r\n */\r\n abstract toRequestsDict(): RequestsProxyConfigDict;\r\n\r\n /**\r\n * If you are using rotating proxies, it can be useful to prevent the HTTP\r\n * client from keeping TCP connections alive, as your IP won't be rotated on\r\n * every request if your connection stays open.\r\n * @returns {boolean} Whether to prevent keeping connections alive\r\n */\r\n get preventKeepingConnectionsAlive(): boolean {\r\n return false;\r\n }\r\n\r\n /**\r\n * Defines how many times we should retry if a request is blocked. When using\r\n * rotating residential proxies with a large IP pool it can make sense to retry a\r\n * couple of times when a blocked IP is encountered, since a retry will trigger\r\n * an IP rotation and the next IP might not be blocked.\r\n * @returns {number} Number of retries when blocked\r\n */\r\n get retriesWhenBlocked(): number {\r\n return 0;\r\n }\r\n}\r\n\r\n/**\r\n * Generic proxy configuration that can be used to set up any HTTP/HTTPS/SOCKS proxy.\r\n *\r\n * If only an HTTP or an HTTPS proxy is provided, it will be used for both types of\r\n * connections. However, you will have to provide at least one of the two.\r\n *\r\n * @example\r\n * ```typescript\r\n * const proxyConfig = new GenericProxyConfig({\r\n * httpUrl: 'http://user:pass@proxy.example.com:8080',\r\n * httpsUrl: 'https://user:pass@proxy.example.com:8080'\r\n * });\r\n * ```\r\n */\r\nexport class GenericProxyConfig extends ProxyConfig {\r\n protected _httpUrl: string | null;\r\n protected _httpsUrl: string | null;\r\n\r\n /**\r\n * Creates a generic proxy configuration.\r\n * If only an HTTP or an HTTPS proxy is provided, it will be used for both types of\r\n * connections. However, you will have to provide at least one of the two.\r\n *\r\n * @param {Object} options - Proxy configuration options\r\n * @param {string} [options.httpUrl] - The proxy URL used for HTTP requests. Defaults to httpsUrl if not provided.\r\n * @param {string} [options.httpsUrl] - The proxy URL used for HTTPS requests. Defaults to httpUrl if not provided.\r\n * @throws {InvalidProxyConfig} If neither httpUrl nor httpsUrl is provided\r\n */\r\n constructor(options: { httpUrl?: string; httpsUrl?: string }) {\r\n super();\r\n const { httpUrl, httpsUrl } = options;\r\n\r\n if (!httpUrl && !httpsUrl) {\r\n throw new InvalidProxyConfig(\r\n 'GenericProxyConfig requires you to define at least one of the two: http or https'\r\n );\r\n }\r\n\r\n this._httpUrl = httpUrl || null;\r\n this._httpsUrl = httpsUrl || null;\r\n }\r\n\r\n get httpUrl(): string | null {\r\n return this._httpUrl;\r\n }\r\n\r\n get httpsUrl(): string | null {\r\n return this._httpsUrl;\r\n }\r\n\r\n toRequestsDict(): RequestsProxyConfigDict {\r\n return {\r\n http: this.httpUrl || this.httpsUrl!,\r\n https: this.httpsUrl || this.httpUrl!\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Webshare proxy configuration for rotating residential proxies.\r\n *\r\n * Webshare is a provider offering rotating residential proxies, which is the\r\n * most reliable way to work around being blocked by YouTube.\r\n *\r\n * If you don't have a Webshare account yet, you will have to create one\r\n * at https://www.webshare.io/?referral_code=w0xno53eb50g and purchase a \"Residential\"\r\n * proxy package that suits your workload (make sure NOT to purchase \"Proxy Server\"\r\n * or \"Static Residential\"!).\r\n *\r\n * Once you have created an account you only need the \"Proxy Username\" and\r\n * \"Proxy Password\" that you can find in your Webshare settings to set up this config.\r\n *\r\n * @example\r\n * ```typescript\r\n * const proxyConfig = new WebshareProxyConfig({\r\n * proxyUsername: 'your-username',\r\n * proxyPassword: 'your-password',\r\n * filterIpLocations: ['us', 'de']\r\n * });\r\n * ```\r\n */\r\nexport class WebshareProxyConfig extends GenericProxyConfig {\r\n public static readonly DEFAULT_DOMAIN_NAME = 'p.webshare.io';\r\n public static readonly DEFAULT_PORT = 80;\r\n\r\n public readonly proxyUsername: string;\r\n public readonly proxyPassword: string;\r\n public readonly domainName: string;\r\n public readonly proxyPort: number;\r\n private readonly filterIpLocations: string[];\r\n private readonly _retriesWhenBlocked: number;\r\n\r\n /**\r\n * Creates a Webshare proxy configuration.\r\n *\r\n * Once you have created a Webshare account and purchased a \"Residential\" package\r\n * (make sure NOT to purchase \"Proxy Server\" or \"Static Residential\"!), this config\r\n * class allows you to easily use it by defaulting to the most reliable proxy settings\r\n * (rotating residential proxies).\r\n *\r\n * @param {Object} options - Webshare configuration options\r\n * @param {string} options.proxyUsername - \"Proxy Username\" found at https://dashboard.webshare.io/proxy/settings\r\n * @param {string} options.proxyPassword - \"Proxy Password\" found at https://dashboard.webshare.io/proxy/settings\r\n * @param {string[]} [options.filterIpLocations] - If you want to limit the pool of IPs to specific countries,\r\n * provide a list of location codes (e.g., ['us', 'de']). This can reduce latency and work around location-based restrictions.\r\n * @param {number} [options.retriesWhenBlocked=10] - How many times to retry if a request is blocked\r\n * @param {string} [options.domainName] - Custom domain name (defaults to p.webshare.io)\r\n * @param {number} [options.proxyPort] - Custom proxy port (defaults to 80)\r\n */\r\n constructor(options: {\r\n proxyUsername: string;\r\n proxyPassword: string;\r\n filterIpLocations?: string[];\r\n retriesWhenBlocked?: number;\r\n domainName?: string;\r\n proxyPort?: number;\r\n }) {\r\n super({ httpUrl: 'placeholder' });\r\n\r\n this.proxyUsername = options.proxyUsername;\r\n this.proxyPassword = options.proxyPassword;\r\n this.domainName = options.domainName || WebshareProxyConfig.DEFAULT_DOMAIN_NAME;\r\n this.proxyPort = options.proxyPort || WebshareProxyConfig.DEFAULT_PORT;\r\n this.filterIpLocations = options.filterIpLocations || [];\r\n this._retriesWhenBlocked = options.retriesWhenBlocked ?? 10;\r\n }\r\n\r\n /**\r\n * Gets the full proxy URL with location filtering and rotation settings.\r\n * @returns {string} The complete proxy URL\r\n */\r\n get url(): string {\r\n const locationCodes = this.filterIpLocations\r\n .map(code => `-${code.toUpperCase()}`)\r\n .join('');\r\n\r\n let username = this.proxyUsername;\r\n const suffix = '-rotate';\r\n\r\n if (username.endsWith(suffix)) {\r\n username = username.slice(0, -suffix.length);\r\n }\r\n\r\n return (\r\n `http://${username}${locationCodes}${suffix}:${this.proxyPassword}` +\r\n `@${this.domainName}:${this.proxyPort}/`\r\n );\r\n }\r\n\r\n get httpUrl(): string {\r\n return this.url;\r\n }\r\n\r\n get httpsUrl(): string {\r\n return this.url;\r\n }\r\n\r\n toRequestsDict(): RequestsProxyConfigDict {\r\n return {\r\n http: this.url,\r\n https: this.url\r\n };\r\n }\r\n\r\n get preventKeepingConnectionsAlive(): boolean {\r\n return true;\r\n }\r\n\r\n get retriesWhenBlocked(): number {\r\n return this._retriesWhenBlocked;\r\n }\r\n}\r\n","/**\r\n * @fileoverview All formatter classes for transcript formatting\r\n */\r\n\r\nimport type { FetchedTranscript } from '../models/fetched-transcript';\r\nimport type { FetchedTranscriptSnippet } from '../types';\r\n\r\n/**\r\n * Base abstract class for all transcript formatters.\r\n */\r\nexport abstract class Formatter {\r\n abstract formatTranscript(transcript: FetchedTranscript, options?: any): string;\r\n abstract formatTranscripts(transcripts: FetchedTranscript[], options?: any): string;\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to pretty-printed JSON format.\r\n */\r\nexport class PrettyPrintFormatter extends Formatter {\r\n formatTranscript(transcript: FetchedTranscript): string {\r\n return JSON.stringify(transcript.toRawData(), null, 2);\r\n }\r\n\r\n formatTranscripts(transcripts: FetchedTranscript[]): string {\r\n return JSON.stringify(transcripts.map(t => t.toRawData()), null, 2);\r\n }\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to JSON format.\r\n */\r\nexport class JSONFormatter extends Formatter {\r\n formatTranscript(transcript: FetchedTranscript, options?: { indent?: number }): string {\r\n return JSON.stringify(transcript.toRawData(), null, options?.indent);\r\n }\r\n\r\n formatTranscripts(transcripts: FetchedTranscript[], options?: { indent?: number }): string {\r\n return JSON.stringify(transcripts.map(t => t.toRawData()), null, options?.indent);\r\n }\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to plain text format with no timestamps.\r\n */\r\nexport class TextFormatter extends Formatter {\r\n formatTranscript(transcript: FetchedTranscript): string {\r\n return transcript.snippets.map(snippet => snippet.text).join('\\n');\r\n }\r\n\r\n formatTranscripts(transcripts: FetchedTranscript[]): string {\r\n return transcripts.map(t => this.formatTranscript(t)).join('\\n\\n\\n');\r\n }\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to article format with character-to-timestamp mappings.\r\n * Returns full text as a string along with character position to time pairings.\r\n */\r\nexport class ArticleFormatter extends Formatter {\r\n formatTranscript(transcript: FetchedTranscript): string {\r\n // Build full text content\r\n const fullText = transcript.snippets.map(snippet => snippet.text).join(' ');\r\n\r\n // Build timestamp mappings - track which character position corresponds to which time\r\n const timestamps: Array<[number, number]> = [];\r\n let charPosition = 0;\r\n\r\n for (const snippet of transcript.snippets) {\r\n // Record the character position and start time for this snippet\r\n timestamps.push([charPosition, snippet.start]);\r\n charPosition += snippet.text.length + 1; // +1 for the space separator\r\n }\r\n\r\n // Calculate character-per-second speeds at intervals\r\n const speedsEveryCharPeriod: { [key: number]: number } = {};\r\n const valueCharPeriod = 100;\r\n\r\n for (const [char, time] of timestamps) {\r\n const speed = Math.floor(char / time) - 10;\r\n speedsEveryCharPeriod[Math.floor(char / valueCharPeriod)] = speed;\r\n }\r\n\r\n // Compress the speed data\r\n const speeds = Object.keys(speedsEveryCharPeriod).map(\r\n (timeKey) => speedsEveryCharPeriod[parseInt(timeKey)]\r\n );\r\n\r\n const compressed: number[] = [];\r\n const compressedCount: number[] = [];\r\n let currentNum = speeds[0];\r\n let count = 1;\r\n\r\n for (let i = 1; i < speeds.length; i++) {\r\n if (speeds[i] === currentNum) {\r\n count++;\r\n } else {\r\n compressed.push(currentNum);\r\n compressedCount.push(count);\r\n currentNum = speeds[i];\r\n count = 1;\r\n }\r\n }\r\n compressed.push(currentNum);\r\n compressedCount.push(count);\r\n\r\n // Convert counts to cumulative positions\r\n let total = 0;\r\n const cumulativeCounts = compressedCount.map((c) => {\r\n total += c;\r\n return total;\r\n });\r\n\r\n // Format output with speeds and timestamps\r\n const speedsData = compressed.join(',') + ' ' + cumulativeCounts.join(',');\r\n\r\n // Remove extra spaces from full text\r\n const cleanedText = fullText.replace(/\\s+/g, ' ');\r\n\r\n return JSON.stringify({\r\n text: cleanedText,\r\n timestamps: speedsData,\r\n wordCount: cleanedText.split(/\\s+/).length,\r\n charCount: cleanedText.length\r\n }, null, 2);\r\n }\r\n\r\n formatTranscripts(transcripts: FetchedTranscript[]): string {\r\n return transcripts.map(t => this.formatTranscript(t)).join('\\n\\n');\r\n }\r\n}\r\n\r\n/**\r\n * Base class for subtitle formatters (SRT, WebVTT).\r\n */\r\nabstract class SubtitleFormatterBase extends TextFormatter {\r\n protected abstract formatTimestamp(h: number, m: number, s: number, ms: number): string;\r\n protected abstract formatTranscriptHeader(lines: string[]): string;\r\n protected abstract formatSubtitleEntry(index: number, timeRange: string, snippet: FetchedTranscriptSnippet): string;\r\n\r\n protected secondsToTimestamp(timeInSeconds: number): string {\r\n const hours = Math.floor(timeInSeconds / 3600);\r\n const remainder = timeInSeconds % 3600;\r\n const minutes = Math.floor(remainder / 60);\r\n const seconds = Math.floor(remainder % 60);\r\n const milliseconds = Math.round((timeInSeconds - Math.floor(timeInSeconds)) * 1000);\r\n\r\n return this.formatTimestamp(hours, minutes, seconds, milliseconds);\r\n }\r\n\r\n formatTranscript(transcript: FetchedTranscript): string {\r\n const formattedLines: string[] = [];\r\n\r\n for (let i = 0; i < transcript.snippets.length; i++) {\r\n const snippet = transcript.snippets[i];\r\n const snippetEndTime = snippet.start + snippet.duration;\r\n\r\n const actualEndTime =\r\n i < transcript.snippets.length - 1 && transcript.snippets[i + 1].start < snippetEndTime\r\n ? transcript.snippets[i + 1].start\r\n : snippetEndTime;\r\n\r\n const timeRangeText = `${this.secondsToTimestamp(snippet.start)} --> ${this.secondsToTimestamp(actualEndTime)}`;\r\n\r\n formattedLines.push(this.formatSubtitleEntry(i, timeRangeText, snippet));\r\n }\r\n\r\n return this.formatTranscriptHeader(formattedLines);\r\n }\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to SRT (SubRip) format.\r\n */\r\nexport class SRTFormatter extends SubtitleFormatterBase {\r\n protected formatTimestamp(h: number, m: number, s: number, ms: number): string {\r\n const pad = (n: number, w: number) => n.toString().padStart(w, '0');\r\n return `${pad(h, 2)}:${pad(m, 2)}:${pad(s, 2)},${pad(ms, 3)}`;\r\n }\r\n\r\n protected formatTranscriptHeader(lines: string[]): string {\r\n return lines.join('\\n\\n') + '\\n';\r\n }\r\n\r\n protected formatSubtitleEntry(index: number, timeRange: string, snippet: FetchedTranscriptSnippet): string {\r\n return `${index + 1}\\n${timeRange}\\n${snippet.text}`;\r\n }\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to WebVTT format.\r\n */\r\nexport class WebVTTFormatter extends SubtitleFormatterBase {\r\n protected formatTimestamp(h: number, m: number, s: number, ms: number): string {\r\n const pad = (n: number, w: number) => n.toString().padStart(w, '0');\r\n return `${pad(h, 2)}:${pad(m, 2)}:${pad(s, 2)}.${pad(ms, 3)}`;\r\n }\r\n\r\n protected formatTranscriptHeader(lines: string[]): string {\r\n return 'WEBVTT\\n\\n' + lines.join('\\n\\n') + '\\n';\r\n }\r\n\r\n protected formatSubtitleEntry(index: number, timeRange: string, snippet: FetchedTranscriptSnippet): string {\r\n return `${timeRange}\\n${snippet.text}`;\r\n }\r\n}\r\n\r\n/**\r\n * Raised when an unknown formatter type is requested.\r\n */\r\nexport class UnknownFormatterType extends Error {\r\n constructor(formatterType: string) {\r\n super(`Unknown formatter type: ${formatterType}. Available types: json, text, srt, webvtt, pretty, article`);\r\n this.name = 'UnknownFormatterType';\r\n Object.setPrototypeOf(this, UnknownFormatterType.prototype);\r\n }\r\n}\r\n\r\n/**\r\n * Utility class for loading formatters by type string.\r\n */\r\nexport class FormatterLoader {\r\n load(formatterType?: string): Formatter {\r\n const type = formatterType?.toLowerCase() || 'pretty';\r\n\r\n switch (type) {\r\n case 'json':\r\n return new JSONFormatter();\r\n case 'text':\r\n return new TextFormatter();\r\n case 'article':\r\n return new ArticleFormatter();\r\n case 'srt':\r\n return new SRTFormatter();\r\n case 'webvtt':\r\n return new WebVTTFormatter();\r\n case 'pretty':\r\n return new PrettyPrintFormatter();\r\n default:\r\n throw new UnknownFormatterType(type);\r\n }\r\n }\r\n}\r\n","{\n \"name\": \"extract-youtube\",\n \"version\": \"1.0.412\",\n \"description\": \"Fast, no-browser serverless-optimized YouTube transcript extractor, with optional React UI: a floating YouTube player and a synced-transcript modal\",\n \"main\": \"dist/index.cjs\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.mjs\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./react\": {\n \"types\": \"./dist/react/index.d.ts\",\n \"import\": \"./dist/react/index.mjs\",\n \"require\": \"./dist/react/index.cjs\"\n }\n },\n \"//bin\": \"Spelled out as an object with a relative path. npm normalizes the string form itself and prints a notice for it on every publish.\",\n \"bin\": {\n \"extract-youtube\": \"dist/cli.js\"\n },\n \"//files\": \"Publish only what consumers resolve. Without this the tarball also carries test/, jest.config.js, tsconfig*.json and vite.config.ts. Matches extract-webpage and extract-pdf.\",\n \"files\": [\n \"dist\",\n \"src\"\n ],\n \"scripts\": {\n \"clean\": \"node -e \\\"require('fs').rmSync('dist',{recursive:true,force:true})\\\"\",\n \"build\": \"npm run clean && npm run build:lib && npm run build:cli && npm run build:react && npm run build:types\",\n \"build:types\": \"tsc --emitDeclarationOnly --declaration --declarationMap\",\n \"build:lib\": \"vite build\",\n \"build:cli\": \"BUILD_CLI=true vite build\",\n \"build:react\": \"BUILD_REACT=true vite build\",\n \"build:bundle\": \"npm run build:lib && npm run build:cli && npm run build:react\",\n \"build:legacy\": \"tsc\",\n \"ship\": \"npm run build && npx standard-version --release-as patch; npm publish\",\n \"test\": \"jest\",\n \"test:coverage\": \"jest --coverage\",\n \"test:speeds\": \"bun src/cli.ts dQw4w9WgXcQ -f speeds\",\n \"lint\": \"eslint src --ext .ts\",\n \"demo\": \"cd demo && npm install && npm run dev\"\n },\n \"keywords\": [\n \"youtube\",\n \"transcript\",\n \"subtitles\",\n \"captions\",\n \"api\",\n \"serverless\",\n \"lambda\",\n \"vercel\",\n \"cloudflare\",\n \"edge\",\n \"typescript\",\n \"youtube-transcript\",\n \"youtube-transcript-api\",\n \"srt\",\n \"webvtt\",\n \"video\",\n \"parsing\",\n \"extraction\",\n \"optimized\",\n \"react\",\n \"floating-player\",\n \"picture-in-picture\",\n \"video-player\",\n \"youtube-player\",\n \"playlist\"\n ],\n \"author\": \"\",\n \"license\": \"rights.institute/PROSPER\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/OpenSourceAGI/qwksearch-research-agent.git\",\n \"directory\": \"packages/extract-youtube\"\n },\n \"dependencies\": {\n \"fast-xml-parser\": \"^5.11.1\",\n \"html-entities\": \"^2.6.0\",\n \"https-proxy-agent\": \"^9.1.0\",\n \"grab-url\": \"^1.6.22\",\n \"youtube-transcript-api\": \"^3.0.6\"\n },\n \"peerDependencies\": {\n \"react\": \">=18\",\n \"react-dom\": \">=18\",\n \"lucide-react\": \"^0.300.0 || ^1.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"react\": {\n \"optional\": true\n },\n \"react-dom\": {\n \"optional\": true\n },\n \"lucide-react\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@types/jest\": \"^30.0.0\",\n \"@types/node\": \"^26.5.0\",\n \"@types/react\": \"^19.2.18\",\n \"@types/react-dom\": \"^19.2.7\",\n \"jest\": \"^30.5.1\",\n \"lucide-react\": \"^1.43.0\",\n \"react\": \"^19.2.8\",\n \"react-dom\": \"^19.2.8\",\n \"terser\": \"^5.51.2\",\n \"ts-jest\": \"^29.4.12\",\n \"typescript\": \"npm:@typescript/typescript6@^6.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"engines\": {\n \"node\": \">=14.0.0\"\n }\n}","#!/usr/bin/env node\r\n/**\r\n * @fileoverview CLI for extracting YouTube transcripts\r\n */\r\n\r\nimport { YouTubeTranscriptApi } from './youtube-transcript-api';\r\nimport { encodeTranscriptSpeeds } from './utils/transcript-utils';\r\nimport { GenericProxyConfig, WebshareProxyConfig } from './proxies';\r\nimport {\r\n JSONFormatter,\r\n TextFormatter,\r\n SRTFormatter,\r\n WebVTTFormatter,\r\n PrettyPrintFormatter\r\n} from './formatters';\r\n\r\ninterface CliOptions {\r\n videoId: string;\r\n languages?: string[];\r\n format?: 'json' | 'text' | 'srt' | 'webvtt' | 'pretty' | 'speeds';\r\n preserveFormatting?: boolean;\r\n proxy?: string;\r\n webshareUser?: string;\r\n websharePass?: string;\r\n help?: boolean;\r\n version?: boolean;\r\n}\r\n\r\nfunction parseArgs(): CliOptions {\r\n const args = process.argv.slice(2);\r\n const options: CliOptions = { videoId: '' };\r\n\r\n for (let i = 0; i < args.length; i++) {\r\n const arg = args[i];\r\n\r\n switch (arg) {\r\n case '-h':\r\n case '--help':\r\n options.help = true;\r\n break;\r\n case '-v':\r\n case '--version':\r\n options.version = true;\r\n break;\r\n case '-l':\r\n case '--languages':\r\n options.languages = args[++i]?.split(',').map(l => l.trim());\r\n break;\r\n case '-f':\r\n case '--format':\r\n options.format = args[++i] as CliOptions['format'];\r\n break;\r\n case '-p':\r\n case '--preserve-formatting':\r\n options.preserveFormatting = true;\r\n break;\r\n case '--proxy':\r\n options.proxy = args[++i];\r\n break;\r\n case '--webshare-user':\r\n options.webshareUser = args[++i];\r\n break;\r\n case '--webshare-pass':\r\n options.websharePass = args[++i];\r\n break;\r\n default:\r\n if (!arg.startsWith('-') && !options.videoId) {\r\n options.videoId = arg;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n return options;\r\n}\r\n\r\nfunction showHelp() {\r\n console.log(`\r\nextract-youtube - Extract YouTube video transcripts\r\n\r\nUSAGE:\r\n extract-youtube <video-id> [options]\r\n\r\nOPTIONS:\r\n -h, --help Show this help message\r\n -v, --version Show version number\r\n -l, --languages <codes> Comma-separated language codes (e.g., en,de,fr)\r\n -f, --format <type> Output format: json, text, srt, webvtt, pretty, speeds (default: json)\r\n -p, --preserve-formatting Preserve text formatting (line breaks, etc.)\r\n --proxy <url> HTTP/HTTPS proxy URL\r\n --webshare-user <username> Webshare proxy username\r\n --webshare-pass <password> Webshare proxy password\r\n\r\nEXAMPLES:\r\n # Extract transcript in JSON format\r\n extract-youtube jNQXAC9IVRw\r\n\r\n # Extract transcript in SRT format\r\n extract-youtube jNQXAC9IVRw -f srt\r\n\r\n # Extract transcript with specific languages\r\n extract-youtube jNQXAC9IVRw -l en,de\r\n\r\n # Extract transcript with proxy\r\n extract-youtube jNQXAC9IVRw --proxy http://proxy.example.com:8080\r\n\r\n # Extract transcript with Webshare proxy\r\n extract-youtube jNQXAC9IVRw --webshare-user myuser --webshare-pass mypass\r\n\r\n # Extract transcript as plain text with preserved formatting\r\n extract-youtube jNQXAC9IVRw -f text -p\r\n\r\n # Extract speech speed encoding with joined text and timestamps\r\n extract-youtube jNQXAC9IVRw -f speeds\r\n`);\r\n}\r\n\r\nfunction showVersion() {\r\n const pkg = require('../package.json');\r\n console.log(`extract-youtube v${pkg.version}`);\r\n}\r\n\r\nasync function main() {\r\n const options = parseArgs();\r\n\r\n if (options.help) {\r\n showHelp();\r\n process.exit(0);\r\n }\r\n\r\n if (options.version) {\r\n showVersion();\r\n process.exit(0);\r\n }\r\n\r\n if (!options.videoId) {\r\n console.error('Error: Video ID is required\\n');\r\n showHelp();\r\n process.exit(1);\r\n }\r\n\r\n try {\r\n // Setup proxy configuration\r\n let proxyConfig;\r\n if (options.webshareUser && options.websharePass) {\r\n proxyConfig = new WebshareProxyConfig({\r\n proxyUsername: options.webshareUser,\r\n proxyPassword: options.websharePass\r\n });\r\n } else if (options.proxy) {\r\n proxyConfig = new GenericProxyConfig({\r\n httpUrl: options.proxy\r\n });\r\n }\r\n\r\n // Create API instance\r\n const api = new YouTubeTranscriptApi({ proxyConfig });\r\n\r\n // Fetch transcript\r\n const transcript = await api.fetchTranscript(options.videoId, {\r\n languages: options.languages,\r\n preserveFormatting: options.preserveFormatting\r\n });\r\n\r\n // Format output\r\n const format = options.format || 'json';\r\n let output: string;\r\n\r\n switch (format) {\r\n case 'json':\r\n output = new JSONFormatter().formatTranscript(transcript);\r\n break;\r\n case 'text':\r\n output = new TextFormatter().formatTranscript(transcript);\r\n break;\r\n case 'srt':\r\n output = new SRTFormatter().formatTranscript(transcript);\r\n break;\r\n case 'webvtt':\r\n output = new WebVTTFormatter().formatTranscript(transcript);\r\n break;\r\n case 'pretty':\r\n output = new PrettyPrintFormatter().formatTranscript(transcript);\r\n break;\r\n case 'speeds': {\r\n const { html, word_count, speeds } = encodeTranscriptSpeeds(transcript);\r\n output = JSON.stringify({ html, word_count, speeds });\r\n break;\r\n }\r\n default:\r\n throw new Error(`Unknown format: ${format}`);\r\n }\r\n\r\n console.log(output);\r\n process.exit(0);\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n console.error(`Error: ${error.message}`);\r\n } else {\r\n console.error(`Error: ${String(error)}`);\r\n }\r\n process.exit(1);\r\n }\r\n}\r\n\r\nmain();\r\n"],"x_google_ignoreList":[9,10,11],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","names":["r","n","o","i","l","i","e","l","t","o","t","s","r"],"sources":["../src/errors/index.ts","../src/models/fetched-transcript.ts","../src/parsers/transcript-parser.ts","../src/utils/http-error-handler.ts","../src/models/transcript.ts","../src/models/transcript-list.ts","../src/types/index.ts","../src/fetchers/youtube-data-extractor.ts","../src/fetchers/transcript-list-fetcher.ts","../../../node_modules/.bun/grab-url@1.6.22/node_modules/grab-url/dist/log.es.js","../../../node_modules/.bun/grab-url@1.6.22/node_modules/grab-url/dist/core-BX1uvK6L.js","../../../node_modules/.bun/grab-url@1.6.22/node_modules/grab-url/dist/grab-api.es.js","../src/http/fetch-http-client.ts","../src/youtube-transcript-api.ts","../src/utils/transcript-utils.ts","../src/proxies/index.ts","../src/formatters/index.ts","../package.json","../src/cli.ts"],"sourcesContent":["/**\r\n * @fileoverview All error classes for the YouTube Transcript API\r\n */\r\n\r\nimport type { ProxyConfig } from '../proxies';\r\n\r\nconst YOUTUBE_WATCH_URL = 'https://www.youtube.com/watch?v={video_id}';\r\n\r\n/**\r\n * Base exception class for all YouTube Transcript API errors.\r\n */\r\nexport class YouTubeTranscriptApiException extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'YouTubeTranscriptApiException';\r\n Object.setPrototypeOf(this, YouTubeTranscriptApiException.prototype);\r\n }\r\n}\r\n\r\n/**\r\n * Base exception class for transcript retrieval errors.\r\n */\r\nexport class CouldNotRetrieveTranscript extends YouTubeTranscriptApiException {\r\n private static readonly ERROR_MESSAGE = '\\nCould not retrieve a transcript for the video {video_url}!';\r\n private static readonly CAUSE_MESSAGE_INTRO = ' This is most likely caused by:\\n\\n{cause}';\r\n private static readonly GITHUB_REFERRAL =\r\n '\\n\\nIf you are sure that the described cause is not responsible for this error ' +\r\n 'and that a transcript should be retrievable, please create an issue at ' +\r\n 'https://github.com/jdepoix/youtube-transcript-api/issues. ' +\r\n 'Please add which version of youtube_transcript_api you are using ' +\r\n 'and provide the information needed to replicate the error. ' +\r\n 'Also make sure that there are no open issues which already describe your problem!';\r\n\r\n public videoId: string;\r\n protected causeMessage: string = '';\r\n\r\n constructor(videoId: string) {\r\n super('');\r\n this.videoId = videoId;\r\n Object.setPrototypeOf(this, CouldNotRetrieveTranscript.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n\r\n protected buildErrorMessage(): string {\r\n const videoUrl = YOUTUBE_WATCH_URL.replace('{video_id}', this.videoId);\r\n let errorMessage = CouldNotRetrieveTranscript.ERROR_MESSAGE.replace('{video_url}', videoUrl);\r\n\r\n const cause = this.getCause();\r\n if (cause) {\r\n errorMessage += CouldNotRetrieveTranscript.CAUSE_MESSAGE_INTRO.replace('{cause}', cause);\r\n errorMessage += CouldNotRetrieveTranscript.GITHUB_REFERRAL;\r\n }\r\n\r\n return errorMessage;\r\n }\r\n\r\n protected getCause(): string {\r\n return this.causeMessage;\r\n }\r\n}\r\n\r\n// Cookie errors\r\nexport class CookieError extends YouTubeTranscriptApiException {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'CookieError';\r\n Object.setPrototypeOf(this, CookieError.prototype);\r\n }\r\n}\r\n\r\nexport class CookiePathInvalid extends CookieError {\r\n constructor(cookiePath: string) {\r\n super(`Can't load the provided cookie file: ${cookiePath}`);\r\n this.name = 'CookiePathInvalid';\r\n Object.setPrototypeOf(this, CookiePathInvalid.prototype);\r\n }\r\n}\r\n\r\nexport class CookieInvalid extends CookieError {\r\n constructor(cookiePath: string) {\r\n super(`The cookies provided are not valid (may have expired): ${cookiePath}`);\r\n this.name = 'CookieInvalid';\r\n Object.setPrototypeOf(this, CookieInvalid.prototype);\r\n }\r\n}\r\n\r\n// Video errors\r\nexport class YouTubeDataUnparsable extends CouldNotRetrieveTranscript {\r\n protected causeMessage =\r\n 'The data required to fetch the transcript is not parsable. This should ' +\r\n 'not happen, please open an issue (make sure to include the video ID)!';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'YouTubeDataUnparsable';\r\n Object.setPrototypeOf(this, YouTubeDataUnparsable.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class YouTubeRequestFailed extends CouldNotRetrieveTranscript {\r\n private httpErrorReason: string;\r\n\r\n constructor(videoId: string, httpError: Error) {\r\n super(videoId);\r\n this.httpErrorReason = httpError.message;\r\n this.name = 'YouTubeRequestFailed';\r\n this.message = this.buildErrorMessage();\r\n Object.setPrototypeOf(this, YouTubeRequestFailed.prototype);\r\n }\r\n\r\n protected getCause(): string {\r\n return `Request to YouTube failed: ${this.httpErrorReason}`;\r\n }\r\n}\r\n\r\nexport class VideoUnplayable extends CouldNotRetrieveTranscript {\r\n private unplayableReason: string | null;\r\n private additionalDetails: string[];\r\n\r\n constructor(videoId: string, unplayableReason: string | null, additionalDetails: string[]) {\r\n super(videoId);\r\n this.unplayableReason = unplayableReason;\r\n this.additionalDetails = additionalDetails;\r\n this.name = 'VideoUnplayable';\r\n this.message = this.buildErrorMessage();\r\n Object.setPrototypeOf(this, VideoUnplayable.prototype);\r\n }\r\n\r\n protected getCause(): string {\r\n let reason = this.unplayableReason ?? 'No reason specified!';\r\n\r\n if (this.additionalDetails.length > 0) {\r\n const formattedDetails = this.additionalDetails.map(detail => ` - ${detail}`).join('\\n');\r\n reason = `${reason}\\n\\nAdditional Details:\\n${formattedDetails}`;\r\n }\r\n\r\n return `The video is unplayable for the following reason: ${reason}`;\r\n }\r\n}\r\n\r\nexport class VideoUnavailable extends CouldNotRetrieveTranscript {\r\n protected causeMessage = 'The video is no longer available';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'VideoUnavailable';\r\n Object.setPrototypeOf(this, VideoUnavailable.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class InvalidVideoId extends CouldNotRetrieveTranscript {\r\n protected causeMessage =\r\n 'You provided an invalid video id. Make sure you are using the video id and NOT the url!\\n\\n' +\r\n 'Do NOT run: `new YouTubeTranscriptApi().fetch(\"https://www.youtube.com/watch?v=1234\")`\\n' +\r\n 'Instead run: `new YouTubeTranscriptApi().fetch(\"1234\")`';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'InvalidVideoId';\r\n Object.setPrototypeOf(this, InvalidVideoId.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class AgeRestricted extends CouldNotRetrieveTranscript {\r\n protected causeMessage =\r\n 'This video is age-restricted. Therefore, you are unable to retrieve ' +\r\n 'transcripts for it without authenticating yourself.\\n\\n' +\r\n 'Unfortunately, Cookie Authentication is temporarily unsupported in ' +\r\n 'youtube-transcript-api, as recent changes in YouTube\\'s API broke the previous ' +\r\n 'implementation. I will do my best to re-implement it as soon as possible.';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'AgeRestricted';\r\n Object.setPrototypeOf(this, AgeRestricted.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class FailedToCreateConsentCookie extends CouldNotRetrieveTranscript {\r\n protected causeMessage = 'Failed to automatically give consent to saving cookies';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'FailedToCreateConsentCookie';\r\n Object.setPrototypeOf(this, FailedToCreateConsentCookie.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\n// Transcript errors\r\nexport class TranscriptsDisabled extends CouldNotRetrieveTranscript {\r\n protected causeMessage = 'Subtitles are disabled for this video';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'TranscriptsDisabled';\r\n Object.setPrototypeOf(this, TranscriptsDisabled.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class NotTranslatable extends CouldNotRetrieveTranscript {\r\n protected causeMessage = 'The requested language is not translatable';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'NotTranslatable';\r\n Object.setPrototypeOf(this, NotTranslatable.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class TranslationLanguageNotAvailable extends CouldNotRetrieveTranscript {\r\n protected causeMessage = 'The requested translation language is not available';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'TranslationLanguageNotAvailable';\r\n Object.setPrototypeOf(this, TranslationLanguageNotAvailable.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\nexport class NoTranscriptFound extends CouldNotRetrieveTranscript {\r\n private requestedLanguageCodes: string[];\r\n private availableTranscriptData: any;\r\n\r\n constructor(videoId: string, requestedLanguageCodes: string[], availableTranscriptData: any) {\r\n super(videoId);\r\n this.requestedLanguageCodes = requestedLanguageCodes;\r\n this.availableTranscriptData = availableTranscriptData;\r\n this.name = 'NoTranscriptFound';\r\n this.message = this.buildErrorMessage();\r\n Object.setPrototypeOf(this, NoTranscriptFound.prototype);\r\n }\r\n\r\n protected getCause(): string {\r\n const requestedLanguages = this.requestedLanguageCodes.join(', ');\r\n return (\r\n `No transcripts were found for any of the requested language codes: ${requestedLanguages}\\n\\n` +\r\n this.availableTranscriptData.toString()\r\n );\r\n }\r\n}\r\n\r\nexport class PoTokenRequired extends CouldNotRetrieveTranscript {\r\n protected causeMessage =\r\n 'The requested video cannot be retrieved without a PO Token. If this happens, ' +\r\n 'please open a GitHub issue!';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'PoTokenRequired';\r\n Object.setPrototypeOf(this, PoTokenRequired.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n}\r\n\r\n// Network errors\r\nexport class RequestBlocked extends CouldNotRetrieveTranscript {\r\n private static readonly BASE_CAUSE_MESSAGE =\r\n 'YouTube is blocking requests from your IP. This usually is due to one of the ' +\r\n 'following reasons:\\n' +\r\n '- You have done too many requests and your IP has been blocked by YouTube\\n' +\r\n '- You are doing requests from an IP belonging to a cloud provider (like AWS, ' +\r\n 'Google Cloud Platform, Azure, etc.). Unfortunately, most IPs from cloud ' +\r\n 'providers are blocked by YouTube.\\n\\n';\r\n\r\n private static readonly DEFAULT_CAUSE_MESSAGE =\r\n RequestBlocked.BASE_CAUSE_MESSAGE +\r\n 'There are two things you can do to work around this:\\n' +\r\n '1. Use proxies to hide your IP address, as explained in the \"Working around ' +\r\n 'IP bans\" section of the README ' +\r\n '(https://github.com/jdepoix/youtube-transcript-api' +\r\n '?tab=readme-ov-file' +\r\n '#working-around-ip-bans-requestblocked-or-ipblocked-exception).\\n' +\r\n '2. (NOT RECOMMENDED) If you authenticate your requests using cookies, you ' +\r\n 'will be able to continue doing requests for a while. However, YouTube will ' +\r\n 'eventually permanently ban the account that you have used to authenticate ' +\r\n 'with! So only do this if you don\\'t mind your account being banned!';\r\n\r\n private static readonly WITH_GENERIC_PROXY_CAUSE_MESSAGE =\r\n 'YouTube is blocking your requests, despite you using proxies. Keep in mind ' +\r\n 'that a proxy is just a way to hide your real IP behind the IP of that proxy, ' +\r\n 'but there is no guarantee that the IP of that proxy won\\'t be blocked as ' +\r\n 'well.\\n\\n' +\r\n 'The only truly reliable way to prevent IP blocks is rotating through a large ' +\r\n 'pool of residential IPs, by using a provider like Webshare ' +\r\n '(https://www.webshare.io/?referral_code=w0xno53eb50g), which provides you ' +\r\n 'with a pool of >30M residential IPs (make sure to purchase ' +\r\n '\"Residential\" proxies, NOT \"Proxy Server\" or \"Static Residential\"!).\\n\\n' +\r\n 'You will find more information on how to easily integrate Webshare here: ' +\r\n 'https://github.com/jdepoix/youtube-transcript-api' +\r\n '?tab=readme-ov-file#using-webshare';\r\n\r\n private static readonly WITH_WEBSHARE_PROXY_CAUSE_MESSAGE =\r\n 'YouTube is blocking your requests, despite you using Webshare proxies. ' +\r\n 'Please make sure that you have purchased \"Residential\" proxies and ' +\r\n 'NOT \"Proxy Server\" or \"Static Residential\", as those won\\'t work as ' +\r\n 'reliably! The free tier also uses \"Proxy Server\" and will NOT work!\\n\\n' +\r\n 'The only reliable option is using \"Residential\" proxies (not \"Static ' +\r\n 'Residential\"), as this allows you to rotate through a pool of over 30M IPs, ' +\r\n 'which means you will always find an IP that hasn\\'t been blocked by YouTube ' +\r\n 'yet!\\n\\n' +\r\n 'You can support the development of this open source project by making your ' +\r\n 'Webshare purchases through this affiliate link: ' +\r\n 'https://www.webshare.io/?referral_code=w0xno53eb50g \\n\\n' +\r\n 'Thank you for your support! <3';\r\n\r\n private proxyConfig: ProxyConfig | null = null;\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'RequestBlocked';\r\n Object.setPrototypeOf(this, RequestBlocked.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n\r\n withProxyConfig(proxyConfig: ProxyConfig | null): RequestBlocked {\r\n this.proxyConfig = proxyConfig;\r\n this.message = this.buildErrorMessage();\r\n return this;\r\n }\r\n\r\n protected getCause(): string {\r\n // Check class name to avoid circular dependency with instanceof\r\n if (this.proxyConfig && this.proxyConfig.constructor.name === 'WebshareProxyConfig') {\r\n return RequestBlocked.WITH_WEBSHARE_PROXY_CAUSE_MESSAGE;\r\n }\r\n if (this.proxyConfig && this.proxyConfig.constructor.name === 'GenericProxyConfig') {\r\n return RequestBlocked.WITH_GENERIC_PROXY_CAUSE_MESSAGE;\r\n }\r\n return RequestBlocked.DEFAULT_CAUSE_MESSAGE;\r\n }\r\n}\r\n\r\nexport class IpBlocked extends RequestBlocked {\r\n protected causeMessage =\r\n 'YouTube is blocking requests from your IP. This usually is due to one of the ' +\r\n 'following reasons:\\n' +\r\n '- You have done too many requests and your IP has been blocked by YouTube\\n' +\r\n '- You are doing requests from an IP belonging to a cloud provider (like AWS, ' +\r\n 'Google Cloud Platform, Azure, etc.). Unfortunately, most IPs from cloud ' +\r\n 'providers are blocked by YouTube.\\n\\n' +\r\n 'Ways to work around this are explained in the \"Working around IP ' +\r\n 'bans\" section of the README (https://github.com/jdepoix/youtube-transcript-api' +\r\n '?tab=readme-ov-file' +\r\n '#working-around-ip-bans-requestblocked-or-ipblocked-exception).\\n';\r\n\r\n constructor(videoId: string) {\r\n super(videoId);\r\n this.name = 'IpBlocked';\r\n Object.setPrototypeOf(this, IpBlocked.prototype);\r\n this.message = this.buildErrorMessage();\r\n }\r\n\r\n protected getCause(): string {\r\n return this.causeMessage;\r\n }\r\n}\r\n","/**\r\n * @fileoverview FetchedTranscript model representing a complete transcript with all snippets\r\n */\r\n\r\nimport { FetchedTranscriptSnippet } from '../types';\r\n\r\n/**\r\n * Represents a fetched transcript with all its snippets and metadata.\r\n * This class is iterable, allowing you to iterate over transcript snippets.\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcript = await api.fetch('video_id');\r\n * for (const snippet of transcript) {\r\n * console.log(snippet.text);\r\n * }\r\n * ```\r\n */\r\nexport class FetchedTranscript implements Iterable<FetchedTranscriptSnippet> {\r\n /** Array of transcript snippets */\r\n public readonly snippets: FetchedTranscriptSnippet[];\r\n\r\n /** The video ID this transcript belongs to */\r\n public readonly videoId: string;\r\n\r\n /** The language name (e.g., \"English\") */\r\n public readonly language: string;\r\n\r\n /** The language code (e.g., \"en\") */\r\n public readonly languageCode: string;\r\n\r\n /** Whether this transcript was automatically generated */\r\n public readonly isGenerated: boolean;\r\n\r\n /**\r\n * Creates a new FetchedTranscript instance.\r\n *\r\n * @param {FetchedTranscriptSnippet[]} snippets - Array of transcript snippets\r\n * @param {string} videoId - The video ID\r\n * @param {string} language - The language name\r\n * @param {string} languageCode - The language code\r\n * @param {boolean} isGenerated - Whether the transcript is auto-generated\r\n */\r\n constructor(\r\n snippets: FetchedTranscriptSnippet[],\r\n videoId: string,\r\n language: string,\r\n languageCode: string,\r\n isGenerated: boolean\r\n ) {\r\n this.snippets = snippets;\r\n this.videoId = videoId;\r\n this.language = language;\r\n this.languageCode = languageCode;\r\n this.isGenerated = isGenerated;\r\n }\r\n\r\n /**\r\n * Makes the transcript iterable, allowing for...of loops.\r\n *\r\n * @returns {Iterator<FetchedTranscriptSnippet>} Iterator over the snippets\r\n */\r\n [Symbol.iterator](): Iterator<FetchedTranscriptSnippet> {\r\n return this.snippets[Symbol.iterator]();\r\n }\r\n\r\n /**\r\n * Gets a snippet by index.\r\n *\r\n * @param {number} index - The index of the snippet\r\n * @returns {FetchedTranscriptSnippet} The snippet at the given index\r\n */\r\n getSnippetAtIndex(index: number): FetchedTranscriptSnippet {\r\n return this.snippets[index];\r\n }\r\n\r\n /**\r\n * Alias for getSnippetAtIndex() for backward compatibility.\r\n *\r\n * @deprecated Use getSnippetAtIndex() instead\r\n * @param {number} index - The index of the snippet\r\n * @returns {FetchedTranscriptSnippet} The snippet at the given index\r\n */\r\n get(index: number): FetchedTranscriptSnippet {\r\n return this.getSnippetAtIndex(index);\r\n }\r\n\r\n /**\r\n * Gets the total number of snippets in the transcript.\r\n *\r\n * @returns {number} The number of snippets\r\n */\r\n get length(): number {\r\n return this.snippets.length;\r\n }\r\n\r\n /**\r\n * Converts the transcript to raw data format (array of objects).\r\n * This is useful for serialization or when you need plain data objects.\r\n *\r\n * @returns {Array<{text: string, start: number, duration: number}>} Raw transcript data\r\n */\r\n toRawData(): Array<{ text: string; start: number; duration: number }> {\r\n return this.snippets.map(snippet => ({\r\n text: snippet.text,\r\n start: snippet.start,\r\n duration: snippet.duration\r\n }));\r\n }\r\n}\r\n","/**\r\n * @fileoverview Parser for converting YouTube transcript XML data into structured snippets\r\n */\r\n\r\nimport { XMLParser } from 'fast-xml-parser';\r\nimport { decode } from 'html-entities';\r\nimport { FetchedTranscriptSnippet } from '../types';\r\n\r\n/**\r\n * Parses transcript XML data from YouTube into FetchedTranscriptSnippet objects.\r\n *\r\n * @example\r\n * ```typescript\r\n * const parser = new TranscriptParser(false);\r\n * const snippets = parser.parseTranscriptXml(xmlData);\r\n * ```\r\n */\r\nexport class TranscriptParser {\r\n /**\r\n * HTML formatting tags that can be preserved in transcript text.\r\n * These are common formatting tags that provide semantic meaning.\r\n */\r\n private static readonly FORMATTING_TAGS = [\r\n 'strong', // Bold text\r\n 'em', // Emphasized text\r\n 'b', // Bold text (alternative)\r\n 'i', // Italic text\r\n 'mark', // Marked/highlighted text\r\n 'small', // Small text\r\n 'del', // Deleted text\r\n 'ins', // Inserted text\r\n 'sub', // Subscript\r\n 'sup' // Superscript\r\n ];\r\n\r\n private htmlRemovalRegex: RegExp;\r\n\r\n /**\r\n * Creates a new TranscriptParser instance.\r\n *\r\n * @param {boolean} [preserveFormatting=false] - Whether to preserve HTML formatting tags\r\n */\r\n constructor(preserveFormatting: boolean = false) {\r\n this.htmlRemovalRegex = this.buildHtmlRemovalRegex(preserveFormatting);\r\n }\r\n\r\n /**\r\n * Builds a regex pattern for removing HTML tags based on formatting preferences.\r\n *\r\n * @private\r\n * @param {boolean} preserveFormatting - Whether to preserve formatting tags\r\n * @returns {RegExp} The HTML removal regex\r\n */\r\n private buildHtmlRemovalRegex(preserveFormatting: boolean): RegExp {\r\n if (preserveFormatting) {\r\n // Create a regex that removes all tags EXCEPT the formatting tags\r\n const formattingTagsPattern = TranscriptParser.FORMATTING_TAGS.join('|');\r\n const pattern = `<\\\\/?(?!\\\\/?(?:${formattingTagsPattern})\\\\b).*?\\\\b>`;\r\n return new RegExp(pattern, 'gi');\r\n } else {\r\n // Remove all HTML tags\r\n return /<[^>]*>/gi;\r\n }\r\n }\r\n\r\n /**\r\n * Parses raw XML transcript data into an array of transcript snippets.\r\n *\r\n * @param {string} xmlData - The raw XML data from YouTube's transcript API\r\n * @returns {FetchedTranscriptSnippet[]} Array of parsed transcript snippets\r\n *\r\n * @example\r\n * ```typescript\r\n * const parser = new TranscriptParser();\r\n * const snippets = parser.parseTranscriptXml(xmlData);\r\n * for (const snippet of snippets) {\r\n * console.log(`${snippet.start}s: ${snippet.text}`);\r\n * }\r\n * ```\r\n */\r\n parseTranscriptXml(xmlData: string): FetchedTranscriptSnippet[] {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n attributeNamePrefix: '@_'\r\n });\r\n\r\n const parsedXml = parser.parse(xmlData);\r\n const textElements = parsedXml.transcript?.text || [];\r\n\r\n // Ensure textElements is always an array (XMLParser returns single object if only one element)\r\n const elementsArray = Array.isArray(textElements) ? textElements : [textElements];\r\n\r\n return elementsArray\r\n .filter(element => element['#text'])\r\n .map(element => this.parseTranscriptSnippet(element));\r\n }\r\n\r\n /**\r\n * Parses a single XML element into a FetchedTranscriptSnippet.\r\n *\r\n * @private\r\n * @param {any} element - The XML element to parse\r\n * @returns {FetchedTranscriptSnippet} The parsed snippet\r\n */\r\n private parseTranscriptSnippet(element: any): FetchedTranscriptSnippet {\r\n return {\r\n text: this.cleanTranscriptText(element['#text']),\r\n start: this.parseFloatAttribute(element['@_start']),\r\n duration: this.parseFloatAttribute(element['@_dur'])\r\n };\r\n }\r\n\r\n /**\r\n * Parses a string attribute as a float, defaulting to 0 if invalid.\r\n *\r\n * @private\r\n * @param {string | undefined} value - The attribute value to parse\r\n * @returns {number} The parsed float value\r\n */\r\n private parseFloatAttribute(value: string | undefined): number {\r\n return parseFloat(value || '0');\r\n }\r\n\r\n /**\r\n * Cleans transcript text by decoding HTML entities and removing HTML tags.\r\n *\r\n * @private\r\n * @param {string} text - The raw transcript text\r\n * @returns {string} The cleaned text\r\n */\r\n private cleanTranscriptText(text: string): string {\r\n // Ensure text is a string\r\n if (typeof text !== 'string') {\r\n text = String(text || '');\r\n }\r\n const decodedText = decode(text);\r\n return decodedText.replace(this.htmlRemovalRegex, '');\r\n }\r\n}\r\n","/**\r\n * @fileoverview HTTP error handling utilities for YouTube API requests\r\n */\r\n\r\nimport { IpBlocked, YouTubeRequestFailed } from '../errors';\r\n\r\n/**\r\n * Checks an HTTP response and throws appropriate errors if the request failed.\r\n *\r\n * @param {Response} response - The HTTP response to check\r\n * @param {string} videoId - The video ID associated with the request\r\n * @throws {IpBlocked} If status is 429 (Too Many Requests)\r\n * @throws {YouTubeRequestFailed} If status indicates an error\r\n *\r\n * @example\r\n * ```typescript\r\n * const response = await httpClient.get(url);\r\n * handleHttpErrors(response, videoId);\r\n * // If we reach here, the request was successful\r\n * ```\r\n */\r\nexport function handleHttpErrors(response: Response, videoId: string): void {\r\n if (response.status === 429) {\r\n throw new IpBlocked(videoId);\r\n }\r\n\r\n if (!response.ok) {\r\n const errorMessage = `HTTP ${response.status}: ${response.statusText}`;\r\n throw new YouTubeRequestFailed(videoId, new Error(errorMessage));\r\n }\r\n}\r\n","/**\r\n * @fileoverview Transcript model representing a single transcript that can be fetched or translated\r\n */\r\n\r\nimport { HttpClient, TranslationLanguage } from '../types';\r\nimport { NotTranslatable, TranslationLanguageNotAvailable, PoTokenRequired } from '../errors';\r\nimport { FetchedTranscript } from './fetched-transcript';\r\nimport { TranscriptParser } from '../parsers/transcript-parser';\r\nimport { handleHttpErrors } from '../utils/http-error-handler';\r\n\r\n/**\r\n * Represents a transcript that can be fetched or translated.\r\n * You typically obtain Transcript objects from a TranscriptList.\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcriptList = await api.list('video_id');\r\n * const transcript = transcriptList.findTranscript(['en']);\r\n * const fetched = await transcript.fetch();\r\n * ```\r\n */\r\nexport class Transcript {\r\n private httpClient: HttpClient;\r\n\r\n /** The video ID this transcript belongs to */\r\n public readonly videoId: string;\r\n\r\n private transcriptUrl: string;\r\n\r\n /** The language name (e.g., \"English\") */\r\n public readonly language: string;\r\n\r\n /** The language code (e.g., \"en\") */\r\n public readonly languageCode: string;\r\n\r\n /** Whether this transcript was automatically generated */\r\n public readonly isGenerated: boolean;\r\n\r\n /** Available translation languages */\r\n public readonly translationLanguages: TranslationLanguage[];\r\n\r\n private translationLanguagesMap: Record<string, string>;\r\n\r\n /**\r\n * Creates a new Transcript instance.\r\n * You probably don't want to initialize this directly.\r\n * Usually you'll access Transcript objects using a TranscriptList.\r\n *\r\n * @param {HttpClient} httpClient - HTTP client for making requests\r\n * @param {string} videoId - The video ID\r\n * @param {string} transcriptUrl - The transcript URL\r\n * @param {string} language - The language name\r\n * @param {string} languageCode - The language code\r\n * @param {boolean} isGenerated - Whether the transcript is auto-generated\r\n * @param {TranslationLanguage[]} translationLanguages - Available translation languages\r\n */\r\n constructor(\r\n httpClient: HttpClient,\r\n videoId: string,\r\n transcriptUrl: string,\r\n language: string,\r\n languageCode: string,\r\n isGenerated: boolean,\r\n translationLanguages: TranslationLanguage[]\r\n ) {\r\n this.httpClient = httpClient;\r\n this.videoId = videoId;\r\n this.transcriptUrl = transcriptUrl;\r\n this.language = language;\r\n this.languageCode = languageCode;\r\n this.isGenerated = isGenerated;\r\n this.translationLanguages = translationLanguages;\r\n this.translationLanguagesMap = this.buildTranslationLanguagesMap(translationLanguages);\r\n }\r\n\r\n /**\r\n * Builds a map of language codes to language names for quick lookup.\r\n *\r\n * @private\r\n * @param {TranslationLanguage[]} languages - Array of translation languages\r\n * @returns {Record<string, string>} Map of language code to language name\r\n */\r\n private buildTranslationLanguagesMap(languages: TranslationLanguage[]): Record<string, string> {\r\n const map: Record<string, string> = {};\r\n for (const lang of languages) {\r\n map[lang.language_code] = lang.language;\r\n }\r\n return map;\r\n }\r\n\r\n /**\r\n * Loads the actual transcript data from YouTube.\r\n *\r\n * @param {boolean} [preserveFormatting=false] - Whether to keep select HTML text formatting\r\n * @returns {Promise<FetchedTranscript>} The fetched transcript with all snippets\r\n * @throws {PoTokenRequired} If a PO Token is required for this video\r\n * @throws {YouTubeRequestFailed} If the HTTP request fails\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcript = transcriptList.findTranscript(['en']);\r\n * const fetched = await transcript.fetch();\r\n *\r\n * // With formatting preserved\r\n * const fetchedWithFormatting = await transcript.fetch(true);\r\n * ```\r\n */\r\n async fetch(preserveFormatting: boolean = false): Promise<FetchedTranscript> {\r\n if (this.transcriptUrl.includes('&exp=xpe')) {\r\n throw new PoTokenRequired(this.videoId);\r\n }\r\n\r\n const response = await this.httpClient.get(this.transcriptUrl);\r\n handleHttpErrors(response, this.videoId);\r\n\r\n const xmlData = await response.text();\r\n const parser = new TranscriptParser(preserveFormatting);\r\n const snippets = parser.parseTranscriptXml(xmlData);\r\n\r\n return new FetchedTranscript(\r\n snippets,\r\n this.videoId,\r\n this.language,\r\n this.languageCode,\r\n this.isGenerated\r\n );\r\n }\r\n\r\n /**\r\n * Checks whether this transcript can be translated to other languages.\r\n *\r\n * @returns {boolean} True if the transcript supports translation\r\n */\r\n get isTranslatable(): boolean {\r\n return this.translationLanguages.length > 0;\r\n }\r\n\r\n /**\r\n * Creates a translated version of this transcript.\r\n *\r\n * @param {string} targetLanguageCode - The target language code (e.g., 'de', 'fr')\r\n * @returns {Transcript} A new Transcript object for the translated transcript\r\n * @throws {NotTranslatable} If the transcript cannot be translated\r\n * @throws {TranslationLanguageNotAvailable} If the requested language is not available\r\n *\r\n * @example\r\n * ```typescript\r\n * const englishTranscript = transcriptList.findTranscript(['en']);\r\n * if (englishTranscript.isTranslatable) {\r\n * const germanTranscript = englishTranscript.translate('de');\r\n * const fetched = await germanTranscript.fetch();\r\n * }\r\n * ```\r\n */\r\n translate(targetLanguageCode: string): Transcript {\r\n if (!this.isTranslatable) {\r\n throw new NotTranslatable(this.videoId);\r\n }\r\n\r\n if (!(targetLanguageCode in this.translationLanguagesMap)) {\r\n throw new TranslationLanguageNotAvailable(this.videoId);\r\n }\r\n\r\n const translatedUrl = `${this.transcriptUrl}&tlang=${targetLanguageCode}`;\r\n const translatedLanguage = this.translationLanguagesMap[targetLanguageCode];\r\n\r\n return new Transcript(\r\n this.httpClient,\r\n this.videoId,\r\n translatedUrl,\r\n translatedLanguage,\r\n targetLanguageCode,\r\n true,\r\n [] // Translated transcripts cannot be translated again\r\n );\r\n }\r\n\r\n /**\r\n * Returns a string representation of the transcript.\r\n *\r\n * @returns {string} A formatted string representation\r\n */\r\n toString(): string {\r\n const translatableFlag = this.isTranslatable ? '[TRANSLATABLE]' : '';\r\n return `${this.languageCode} (\"${this.language}\")${translatableFlag}`;\r\n }\r\n}\r\n","/**\r\n * @fileoverview TranscriptList model representing all available transcripts for a video\r\n */\r\n\r\nimport { HttpClient, TranslationLanguage, CaptionsJson } from '../types';\r\nimport { Transcript } from './transcript';\r\nimport { NoTranscriptFound } from '../errors';\r\n\r\n/**\r\n * Represents a list of available transcripts for a video.\r\n * This object is iterable and provides methods to search for specific transcripts.\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcriptList = await api.list('video_id');\r\n *\r\n * // Iterate over all transcripts\r\n * for (const transcript of transcriptList) {\r\n * console.log(transcript.language, transcript.languageCode);\r\n * }\r\n *\r\n * // Find a specific transcript\r\n * const transcript = transcriptList.findTranscript(['de', 'en']);\r\n * ```\r\n */\r\nexport class TranscriptList implements Iterable<Transcript> {\r\n /** The video ID this list belongs to */\r\n public readonly videoId: string;\r\n\r\n private manuallyCreatedTranscripts: Record<string, Transcript>;\r\n private autoGeneratedTranscripts: Record<string, Transcript>;\r\n private availableTranslationLanguages: TranslationLanguage[];\r\n\r\n /**\r\n * Creates a new TranscriptList instance.\r\n * The constructor is only for internal use. Use the static buildFromCaptionsJson method instead.\r\n *\r\n * @param {string} videoId - The video ID\r\n * @param {Record<string, Transcript>} manuallyCreatedTranscripts - Map of manually created transcripts\r\n * @param {Record<string, Transcript>} autoGeneratedTranscripts - Map of auto-generated transcripts\r\n * @param {TranslationLanguage[]} availableTranslationLanguages - Available translation languages\r\n */\r\n constructor(\r\n videoId: string,\r\n manuallyCreatedTranscripts: Record<string, Transcript>,\r\n autoGeneratedTranscripts: Record<string, Transcript>,\r\n availableTranslationLanguages: TranslationLanguage[]\r\n ) {\r\n this.videoId = videoId;\r\n this.manuallyCreatedTranscripts = manuallyCreatedTranscripts;\r\n this.autoGeneratedTranscripts = autoGeneratedTranscripts;\r\n this.availableTranslationLanguages = availableTranslationLanguages;\r\n }\r\n\r\n /**\r\n * Factory method to build a TranscriptList from YouTube's captions JSON data.\r\n *\r\n * @param {HttpClient} httpClient - HTTP client for making requests\r\n * @param {string} videoId - The video ID\r\n * @param {CaptionsJson} captionsJson - The JSON parsed from YouTube's response\r\n * @returns {TranscriptList} The created TranscriptList\r\n */\r\n static buildFromCaptionsJson(\r\n httpClient: HttpClient,\r\n videoId: string,\r\n captionsJson: CaptionsJson\r\n ): TranscriptList {\r\n const translationLanguages = TranscriptList.extractTranslationLanguages(captionsJson);\r\n const { manualTranscripts, generatedTranscripts } = TranscriptList.categorizeTranscripts(\r\n httpClient,\r\n videoId,\r\n captionsJson,\r\n translationLanguages\r\n );\r\n\r\n return new TranscriptList(videoId, manualTranscripts, generatedTranscripts, translationLanguages);\r\n }\r\n\r\n /**\r\n * Extracts translation languages from the captions JSON.\r\n *\r\n * @private\r\n * @param {CaptionsJson} captionsJson - The captions JSON data\r\n * @returns {TranslationLanguage[]} Array of translation languages\r\n */\r\n private static extractTranslationLanguages(captionsJson: CaptionsJson): TranslationLanguage[] {\r\n return (captionsJson.translationLanguages || []).map(lang => ({\r\n language: lang.languageName.runs[0].text,\r\n language_code: lang.languageCode\r\n }));\r\n }\r\n\r\n /**\r\n * Categorizes transcripts into manually created and auto-generated.\r\n *\r\n * @private\r\n * @param {HttpClient} httpClient - HTTP client for making requests\r\n * @param {string} videoId - The video ID\r\n * @param {CaptionsJson} captionsJson - The captions JSON data\r\n * @param {TranslationLanguage[]} translationLanguages - Available translation languages\r\n * @returns {{manualTranscripts: Record<string, Transcript>, generatedTranscripts: Record<string, Transcript>}}\r\n */\r\n private static categorizeTranscripts(\r\n httpClient: HttpClient,\r\n videoId: string,\r\n captionsJson: CaptionsJson,\r\n translationLanguages: TranslationLanguage[]\r\n ): {\r\n manualTranscripts: Record<string, Transcript>;\r\n generatedTranscripts: Record<string, Transcript>;\r\n } {\r\n const manualTranscripts: Record<string, Transcript> = {};\r\n const generatedTranscripts: Record<string, Transcript> = {};\r\n\r\n for (const captionTrack of captionsJson.captionTracks) {\r\n const isAutoGenerated = captionTrack.kind === 'asr';\r\n const targetMap = isAutoGenerated ? generatedTranscripts : manualTranscripts;\r\n\r\n // Remove format parameter from URL for better compatibility\r\n const cleanedUrl = captionTrack.baseUrl.replace('&fmt=srv3', '');\r\n\r\n const transcript = new Transcript(\r\n httpClient,\r\n videoId,\r\n cleanedUrl,\r\n captionTrack.name.runs[0].text,\r\n captionTrack.languageCode,\r\n isAutoGenerated,\r\n captionTrack.isTranslatable ? translationLanguages : []\r\n );\r\n\r\n targetMap[captionTrack.languageCode] = transcript;\r\n }\r\n\r\n return { manualTranscripts, generatedTranscripts };\r\n }\r\n\r\n /**\r\n * Makes the transcript list iterable, allowing for...of loops.\r\n * Manual transcripts are yielded first, followed by auto-generated transcripts.\r\n *\r\n * @returns {Iterator<Transcript>} Iterator over all transcripts\r\n */\r\n [Symbol.iterator](): Iterator<Transcript> {\r\n const manualTranscripts = Object.values(this.manuallyCreatedTranscripts);\r\n const generatedTranscripts = Object.values(this.autoGeneratedTranscripts);\r\n return [...manualTranscripts, ...generatedTranscripts][Symbol.iterator]();\r\n }\r\n\r\n /**\r\n * Finds a transcript for given language codes. Manually created transcripts are\r\n * returned first and only if none are found, auto-generated transcripts are used.\r\n *\r\n * @param {string[]} languageCodes - A list of language codes in descending priority\r\n * @returns {Transcript} The found transcript\r\n * @throws {NoTranscriptFound} If no transcript is found for any of the language codes\r\n *\r\n * @example\r\n * ```typescript\r\n * // Try German first, then English\r\n * const transcript = transcriptList.findTranscript(['de', 'en']);\r\n * ```\r\n */\r\n findTranscript(languageCodes: string[]): Transcript {\r\n return this.findTranscriptInMaps(languageCodes, [\r\n this.manuallyCreatedTranscripts,\r\n this.autoGeneratedTranscripts\r\n ]);\r\n }\r\n\r\n /**\r\n * Finds an automatically generated transcript for given language codes.\r\n *\r\n * @param {string[]} languageCodes - A list of language codes in descending priority\r\n * @returns {Transcript} The found auto-generated transcript\r\n * @throws {NoTranscriptFound} If no auto-generated transcript is found\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcript = transcriptList.findGeneratedTranscript(['en']);\r\n * ```\r\n */\r\n findGeneratedTranscript(languageCodes: string[]): Transcript {\r\n return this.findTranscriptInMaps(languageCodes, [this.autoGeneratedTranscripts]);\r\n }\r\n\r\n /**\r\n * Finds a manually created transcript for given language codes.\r\n *\r\n * @param {string[]} languageCodes - A list of language codes in descending priority\r\n * @returns {Transcript} The found manually created transcript\r\n * @throws {NoTranscriptFound} If no manually created transcript is found\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcript = transcriptList.findManuallyCreatedTranscript(['en']);\r\n * ```\r\n */\r\n findManuallyCreatedTranscript(languageCodes: string[]): Transcript {\r\n return this.findTranscriptInMaps(languageCodes, [this.manuallyCreatedTranscripts]);\r\n }\r\n\r\n /**\r\n * Internal method to find a transcript by searching through provided maps.\r\n *\r\n * @private\r\n * @param {string[]} languageCodes - Language codes to search for\r\n * @param {Record<string, Transcript>[]} transcriptMaps - Maps to search through\r\n * @returns {Transcript} The found transcript\r\n * @throws {NoTranscriptFound} If no transcript is found\r\n */\r\n private findTranscriptInMaps(\r\n languageCodes: string[],\r\n transcriptMaps: Record<string, Transcript>[]\r\n ): Transcript {\r\n for (const languageCode of languageCodes) {\r\n for (const transcriptMap of transcriptMaps) {\r\n if (languageCode in transcriptMap) {\r\n return transcriptMap[languageCode];\r\n }\r\n }\r\n }\r\n\r\n throw new NoTranscriptFound(this.videoId, languageCodes, this);\r\n }\r\n\r\n /**\r\n * Returns a formatted string representation of all available transcripts.\r\n *\r\n * @returns {string} A formatted string showing all available transcripts\r\n */\r\n toString(): string {\r\n const formatTranscriptMap = (transcripts: Record<string, Transcript>): string => {\r\n const descriptions = Object.values(transcripts).map(t => ` - ${t.toString()}`);\r\n return descriptions.length > 0 ? descriptions.join('\\n') : 'None';\r\n };\r\n\r\n const formatTranslationLanguages = (): string => {\r\n const descriptions = this.availableTranslationLanguages.map(\r\n lang => ` - ${lang.language_code} (\"${lang.language}\")`\r\n );\r\n return descriptions.length > 0 ? descriptions.join('\\n') : 'None';\r\n };\r\n\r\n return (\r\n `For this video (${this.videoId}) transcripts are available in the following languages:\\n\\n` +\r\n `(MANUALLY CREATED)\\n${formatTranscriptMap(this.manuallyCreatedTranscripts)}\\n\\n` +\r\n `(GENERATED)\\n${formatTranscriptMap(this.autoGeneratedTranscripts)}\\n\\n` +\r\n `(TRANSLATION LANGUAGES)\\n${formatTranslationLanguages()}`\r\n );\r\n }\r\n}\r\n","/**\r\n * @fileoverview Type definitions for the YouTube Transcript API\r\n */\r\n\r\n/**\r\n * Represents a single snippet/cue of a transcript\r\n */\r\nexport interface FetchedTranscriptSnippet {\r\n /** The text content of this transcript snippet */\r\n text: string;\r\n /** The timestamp at which this transcript snippet appears on screen in seconds */\r\n start: number;\r\n /**\r\n * The duration of how long the snippet stays on screen in seconds.\r\n * Note: This is not the duration of the transcribed speech, but how long\r\n * the snippet stays on screen. Therefore, there can be overlaps between snippets!\r\n */\r\n duration: number;\r\n}\r\n\r\n/**\r\n * Translation language information\r\n */\r\nexport interface TranslationLanguage {\r\n /** The name of the language */\r\n language: string;\r\n /** The language code (e.g., 'en', 'de', 'fr') */\r\n language_code: string;\r\n}\r\n\r\n/**\r\n * Playability status enum values\r\n */\r\nexport enum PlayabilityStatus {\r\n OK = 'OK',\r\n ERROR = 'ERROR',\r\n LOGIN_REQUIRED = 'LOGIN_REQUIRED'\r\n}\r\n\r\n/**\r\n * Playability failed reason enum values\r\n */\r\nexport enum PlayabilityFailedReason {\r\n BOT_DETECTED = \"Sign in to confirm you're not a bot\",\r\n AGE_RESTRICTED = 'This video may be inappropriate for some users.',\r\n VIDEO_UNAVAILABLE = 'This video is unavailable'\r\n}\r\n\r\n/**\r\n * Proxy configuration dictionary for HTTP clients\r\n */\r\nexport interface RequestsProxyConfigDict {\r\n http: string;\r\n https: string;\r\n}\r\n\r\n/**\r\n * Caption track data from YouTube API\r\n */\r\nexport interface CaptionTrack {\r\n baseUrl: string;\r\n name: {\r\n runs: Array<{ text: string }>;\r\n };\r\n languageCode: string;\r\n kind?: string;\r\n isTranslatable?: boolean;\r\n}\r\n\r\n/**\r\n * Captions JSON data from YouTube\r\n */\r\nexport interface CaptionsJson {\r\n captionTracks: CaptionTrack[];\r\n translationLanguages?: Array<{\r\n languageName: {\r\n runs: Array<{ text: string }>;\r\n };\r\n languageCode: string;\r\n }>;\r\n}\r\n\r\n/**\r\n * YouTube InnerTube API response\r\n */\r\nexport interface InnerTubeData {\r\n playabilityStatus?: {\r\n status?: string;\r\n reason?: string;\r\n errorScreen?: {\r\n playerErrorMessageRenderer?: {\r\n subreason?: {\r\n runs?: Array<{ text?: string }>;\r\n };\r\n };\r\n };\r\n };\r\n captions?: {\r\n playerCaptionsTracklistRenderer?: CaptionsJson;\r\n };\r\n}\r\n\r\n/**\r\n * HTTP client interface with fetch-like API\r\n */\r\nexport interface HttpClient {\r\n get(url: string, options?: RequestInit): Promise<Response>;\r\n post(url: string, options?: RequestInit): Promise<Response>;\r\n}\r\n\r\n/**\r\n * Cookie storage interface\r\n */\r\nexport interface CookieJar {\r\n set(name: string, value: string, domain: string): void;\r\n get(name: string): string | undefined;\r\n}\r\n","/**\r\n * @fileoverview Utilities for extracting data from YouTube HTML and InnerTube API responses\r\n */\r\n\r\nimport {\r\n InnerTubeData,\r\n CaptionsJson,\r\n PlayabilityStatus,\r\n PlayabilityFailedReason\r\n} from '../types';\r\nimport {\r\n IpBlocked,\r\n YouTubeDataUnparsable,\r\n TranscriptsDisabled,\r\n RequestBlocked,\r\n AgeRestricted,\r\n VideoUnavailable,\r\n InvalidVideoId,\r\n VideoUnplayable\r\n} from '../errors';\r\n\r\n/**\r\n * Extracts the InnerTube API key from YouTube's HTML page.\r\n *\r\n * @param {string} htmlContent - The HTML content from YouTube's watch page\r\n * @param {string} videoId - The video ID being processed\r\n * @returns {string} The extracted API key\r\n * @throws {IpBlocked} If the page contains a reCAPTCHA (IP is blocked)\r\n * @throws {YouTubeDataUnparsable} If the API key cannot be found\r\n *\r\n * @example\r\n * ```typescript\r\n * const html = await fetchVideoHtml(videoId);\r\n * const apiKey = extractInnertubeApiKey(html, videoId);\r\n * ```\r\n */\r\nexport function extractInnertubeApiKey(htmlContent: string, videoId: string): string {\r\n const apiKeyPattern = /\"INNERTUBE_API_KEY\":\\s*\"([a-zA-Z0-9_-]+)\"/;\r\n const match = htmlContent.match(apiKeyPattern);\r\n\r\n if (match && match.length === 2) {\r\n return match[1];\r\n }\r\n\r\n // Check if IP is blocked (reCAPTCHA present)\r\n if (htmlContent.includes('class=\"g-recaptcha\"')) {\r\n throw new IpBlocked(videoId);\r\n }\r\n\r\n throw new YouTubeDataUnparsable(videoId);\r\n}\r\n\r\n/**\r\n * Extracts captions JSON from YouTube's InnerTube API response.\r\n *\r\n * @param {InnerTubeData} innertubeData - The InnerTube API response data\r\n * @param {string} videoId - The video ID being processed\r\n * @returns {CaptionsJson} The extracted captions data\r\n * @throws {TranscriptsDisabled} If captions are disabled for the video\r\n *\r\n * @example\r\n * ```typescript\r\n * const innertubeData = await fetchInnertubeData(videoId, apiKey);\r\n * const captionsJson = extractCaptionsJson(innertubeData, videoId);\r\n * ```\r\n */\r\nexport function extractCaptionsJson(innertubeData: InnerTubeData, videoId: string): CaptionsJson {\r\n validatePlayabilityStatus(innertubeData.playabilityStatus, videoId);\r\n\r\n const captionsJson = innertubeData.captions?.playerCaptionsTracklistRenderer;\r\n\r\n if (!captionsJson || !captionsJson.captionTracks) {\r\n throw new TranscriptsDisabled(videoId);\r\n }\r\n\r\n return captionsJson;\r\n}\r\n\r\n/**\r\n * Validates the playability status of a video and throws appropriate errors.\r\n *\r\n * @param {any} playabilityStatusData - The playability status data from InnerTube\r\n * @param {string} videoId - The video ID being validated\r\n * @throws {RequestBlocked} If YouTube detected a bot\r\n * @throws {AgeRestricted} If the video is age-restricted\r\n * @throws {VideoUnavailable} If the video is unavailable\r\n * @throws {InvalidVideoId} If the video ID is invalid (URL was provided instead)\r\n * @throws {VideoUnplayable} If the video is unplayable for any other reason\r\n *\r\n * @example\r\n * ```typescript\r\n * validatePlayabilityStatus(innertubeData.playabilityStatus, videoId);\r\n * ```\r\n */\r\nexport function validatePlayabilityStatus(playabilityStatusData: any, videoId: string): void {\r\n if (!playabilityStatusData) {\r\n return;\r\n }\r\n\r\n const playabilityStatus = playabilityStatusData.status;\r\n\r\n // If status is OK, video is playable\r\n if (playabilityStatus === PlayabilityStatus.OK || !playabilityStatus) {\r\n return;\r\n }\r\n\r\n const reason = playabilityStatusData.reason;\r\n\r\n // Handle LOGIN_REQUIRED status\r\n if (playabilityStatus === PlayabilityStatus.LOGIN_REQUIRED) {\r\n if (reason === PlayabilityFailedReason.BOT_DETECTED) {\r\n throw new RequestBlocked(videoId);\r\n }\r\n if (reason === PlayabilityFailedReason.AGE_RESTRICTED) {\r\n throw new AgeRestricted(videoId);\r\n }\r\n }\r\n\r\n // Handle ERROR status\r\n if (playabilityStatus === PlayabilityStatus.ERROR && reason === PlayabilityFailedReason.VIDEO_UNAVAILABLE) {\r\n // Check if user provided a URL instead of video ID\r\n if (videoId.startsWith('http://') || videoId.startsWith('https://')) {\r\n throw new InvalidVideoId(videoId);\r\n }\r\n throw new VideoUnavailable(videoId);\r\n }\r\n\r\n // Extract additional sub-reasons if available\r\n const subReasons = extractPlayabilitySubreasons(playabilityStatusData);\r\n\r\n throw new VideoUnplayable(videoId, reason, subReasons);\r\n}\r\n\r\n/**\r\n * Extracts sub-reasons from the playability status error screen.\r\n *\r\n * @private\r\n * @param {any} playabilityStatusData - The playability status data\r\n * @returns {string[]} Array of sub-reason messages\r\n */\r\nfunction extractPlayabilitySubreasons(playabilityStatusData: any): string[] {\r\n const runs = playabilityStatusData.errorScreen?.playerErrorMessageRenderer?.subreason?.runs;\r\n\r\n if (!runs || !Array.isArray(runs)) {\r\n return [];\r\n }\r\n\r\n return runs\r\n .map((run: any) => run.text || '')\r\n .filter((text: string) => text.length > 0);\r\n}\r\n","/**\r\n * @fileoverview Fetcher for retrieving transcript lists from YouTube\r\n */\r\n\r\nimport { decode } from 'html-entities';\r\nimport { HttpClient, CaptionsJson, InnerTubeData } from '../types';\r\nimport { ProxyConfig } from '../proxies';\r\nimport { TranscriptList } from '../models/transcript-list';\r\nimport { RequestBlocked, FailedToCreateConsentCookie } from '../errors';\r\nimport { handleHttpErrors } from '../utils/http-error-handler';\r\nimport {\r\n extractInnertubeApiKey,\r\n extractCaptionsJson\r\n} from './youtube-data-extractor';\r\n\r\n/** YouTube watch page URL template */\r\nconst YOUTUBE_WATCH_URL = 'https://www.youtube.com/watch?v={video_id}';\r\n\r\n/** YouTube InnerTube API URL template */\r\nconst INNERTUBE_API_URL = 'https://www.youtube.com/youtubei/v1/player?key={api_key}';\r\n\r\n/** InnerTube API context configuration for requests */\r\nconst INNERTUBE_CONTEXT = {\r\n client: {\r\n clientName: 'ANDROID',\r\n clientVersion: '20.10.38'\r\n }\r\n};\r\n\r\n/**\r\n * Fetches transcript lists from YouTube for given video IDs.\r\n * Handles consent cookies, retries on blocks, and extracts caption data.\r\n *\r\n * @example\r\n * ```typescript\r\n * const fetcher = new TranscriptListFetcher(httpClient, proxyConfig);\r\n * const transcriptList = await fetcher.fetchTranscriptList('dQw4w9WgXcQ');\r\n * ```\r\n */\r\nexport class TranscriptListFetcher {\r\n private httpClient: HttpClient;\r\n private proxyConfig: ProxyConfig | null;\r\n\r\n /**\r\n * Creates a new TranscriptListFetcher instance.\r\n *\r\n * @param {HttpClient} httpClient - The HTTP client to use for requests\r\n * @param {ProxyConfig | null} proxyConfig - Optional proxy configuration\r\n */\r\n constructor(httpClient: HttpClient, proxyConfig: ProxyConfig | null) {\r\n this.httpClient = httpClient;\r\n this.proxyConfig = proxyConfig;\r\n }\r\n\r\n /**\r\n * Fetches the list of available transcripts for a video.\r\n *\r\n * @param {string} videoId - The YouTube video ID\r\n * @returns {Promise<TranscriptList>} The transcript list\r\n * @throws {RequestBlocked} If requests are blocked and retries exhausted\r\n * @throws {IpBlocked} If IP is blocked by YouTube\r\n * @throws {YouTubeDataUnparsable} If YouTube data cannot be parsed\r\n * @throws {TranscriptsDisabled} If transcripts are disabled for the video\r\n *\r\n * @example\r\n * ```typescript\r\n * const transcriptList = await fetcher.fetchTranscriptList('dQw4w9WgXcQ');\r\n * const transcript = transcriptList.findTranscript(['en']);\r\n * ```\r\n */\r\n async fetchTranscriptList(videoId: string): Promise<TranscriptList> {\r\n const captionsJson = await this.fetchCaptionsJsonWithRetry(videoId);\r\n return TranscriptList.buildFromCaptionsJson(this.httpClient, videoId, captionsJson);\r\n }\r\n\r\n /**\r\n * Fetches captions JSON with retry logic for blocked requests.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @param {number} [attemptNumber=0] - Current attempt number (for retry logic)\r\n * @returns {Promise<CaptionsJson>} The captions JSON data\r\n */\r\n private async fetchCaptionsJsonWithRetry(\r\n videoId: string,\r\n attemptNumber: number = 0\r\n ): Promise<CaptionsJson> {\r\n try {\r\n const htmlContent = await this.fetchVideoPageHtml(videoId);\r\n const apiKey = extractInnertubeApiKey(htmlContent, videoId);\r\n const innertubeData = await this.fetchInnertubePlayerData(videoId, apiKey);\r\n return extractCaptionsJson(innertubeData, videoId);\r\n } catch (error) {\r\n if (error instanceof RequestBlocked) {\r\n return this.handleBlockedRequest(error, videoId, attemptNumber);\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Handles blocked requests with retry logic based on proxy configuration.\r\n *\r\n * @private\r\n * @param {RequestBlocked} error - The blocked request error\r\n * @param {string} videoId - The video ID\r\n * @param {number} attemptNumber - Current attempt number\r\n * @returns {Promise<CaptionsJson>} The captions JSON data from retry\r\n * @throws {RequestBlocked} If retries are exhausted\r\n */\r\n private async handleBlockedRequest(\r\n error: RequestBlocked,\r\n videoId: string,\r\n attemptNumber: number\r\n ): Promise<CaptionsJson> {\r\n const maxRetries = this.proxyConfig?.retriesWhenBlocked || 0;\r\n\r\n if (attemptNumber + 1 < maxRetries) {\r\n return this.fetchCaptionsJsonWithRetry(videoId, attemptNumber + 1);\r\n }\r\n\r\n throw error.withProxyConfig(this.proxyConfig);\r\n }\r\n\r\n /**\r\n * Fetches the HTML content of a video's watch page, handling consent cookies.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @returns {Promise<string>} The HTML content\r\n * @throws {FailedToCreateConsentCookie} If consent cookie creation fails\r\n */\r\n private async fetchVideoPageHtml(videoId: string): Promise<string> {\r\n let htmlContent = await this.fetchAndDecodeHtml(videoId);\r\n\r\n // Handle YouTube consent cookie requirement\r\n if (this.isConsentPageDetected(htmlContent)) {\r\n this.createConsentCookie(htmlContent, videoId);\r\n htmlContent = await this.fetchAndDecodeHtml(videoId);\r\n\r\n if (this.isConsentPageDetected(htmlContent)) {\r\n throw new FailedToCreateConsentCookie(videoId);\r\n }\r\n }\r\n\r\n return htmlContent;\r\n }\r\n\r\n /**\r\n * Checks if the HTML content is a consent page.\r\n *\r\n * @private\r\n * @param {string} htmlContent - The HTML content to check\r\n * @returns {boolean} True if consent page detected\r\n */\r\n private isConsentPageDetected(htmlContent: string): boolean {\r\n return htmlContent.includes('action=\"https://consent.youtube.com/s\"');\r\n }\r\n\r\n /**\r\n * Fetches HTML from YouTube watch page and decodes HTML entities.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @returns {Promise<string>} The decoded HTML content\r\n */\r\n private async fetchAndDecodeHtml(videoId: string): Promise<string> {\r\n const url = this.buildWatchUrl(videoId);\r\n const response = await this.httpClient.get(url);\r\n handleHttpErrors(response, videoId);\r\n const rawHtml = await response.text();\r\n return decode(rawHtml);\r\n }\r\n\r\n /**\r\n * Builds the YouTube watch URL for a video ID.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @returns {string} The watch URL\r\n */\r\n private buildWatchUrl(videoId: string): string {\r\n return YOUTUBE_WATCH_URL.replace('{video_id}', videoId);\r\n }\r\n\r\n /**\r\n * Creates a consent cookie from the HTML content.\r\n * Note: This is a placeholder - cookie handling should be implemented in the HTTP client.\r\n *\r\n * @private\r\n * @param {string} htmlContent - The HTML content containing consent form\r\n * @param {string} videoId - The video ID\r\n * @throws {FailedToCreateConsentCookie} If consent value cannot be extracted\r\n */\r\n private createConsentCookie(htmlContent: string, videoId: string): void {\r\n const consentValuePattern = /name=\"v\" value=\"(.*?)\"/;\r\n const match = htmlContent.match(consentValuePattern);\r\n\r\n if (!match) {\r\n throw new FailedToCreateConsentCookie(videoId);\r\n }\r\n\r\n // TODO: Cookie handling would need to be implemented in the HTTP client\r\n // This is a placeholder for the cookie setting logic\r\n }\r\n\r\n /**\r\n * Fetches player data from YouTube's InnerTube API.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @param {string} apiKey - The InnerTube API key\r\n * @returns {Promise<InnerTubeData>} The InnerTube player data\r\n */\r\n private async fetchInnertubePlayerData(videoId: string, apiKey: string): Promise<InnerTubeData> {\r\n const url = this.buildInnertubeApiUrl(apiKey);\r\n const requestBody = this.buildInnertubeRequestBody(videoId);\r\n\r\n const response = await this.httpClient.post(url, {\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(requestBody)\r\n });\r\n\r\n handleHttpErrors(response, videoId);\r\n return (await response.json()) as InnerTubeData;\r\n }\r\n\r\n /**\r\n * Builds the InnerTube API URL with the provided API key.\r\n *\r\n * @private\r\n * @param {string} apiKey - The API key\r\n * @returns {string} The complete API URL\r\n */\r\n private buildInnertubeApiUrl(apiKey: string): string {\r\n return INNERTUBE_API_URL.replace('{api_key}', apiKey);\r\n }\r\n\r\n /**\r\n * Builds the request body for InnerTube API calls.\r\n *\r\n * @private\r\n * @param {string} videoId - The video ID\r\n * @returns {object} The request body\r\n */\r\n private buildInnertubeRequestBody(videoId: string): object {\r\n return {\r\n context: INNERTUBE_CONTEXT,\r\n videoId: videoId\r\n };\r\n }\r\n}\r\n","var e=/* @__PURE__ */(e=>(e.RESET=\"reset\",e.BLACK=\"black\",e.RED=\"red\",e.GREEN=\"green\",e.YELLOW=\"yellow\",e.BLUE=\"blue\",e.MAGENTA=\"magenta\",e.CYAN=\"cyan\",e.WHITE=\"white\",e.GRAY=\"gray\",e.BRIGHT_RED=\"brightRed\",e.BRIGHT_GREEN=\"brightGreen\",e.BRIGHT_YELLOW=\"brightYellow\",e.BRIGHT_BLUE=\"brightBlue\",e.BRIGHT_MAGENTA=\"brightMagenta\",e.BRIGHT_CYAN=\"brightCyan\",e.BRIGHT_WHITE=\"brightWhite\",e.BG_RED=\"bgRed\",e.BG_GREEN=\"bgGreen\",e.BG_YELLOW=\"bgYellow\",e.BG_BLUE=\"bgBlue\",e.BG_MAGENTA=\"bgMagenta\",e.BG_CYAN=\"bgCyan\",e.BG_WHITE=\"bgWhite\",e.BG_GRAY=\"bgGray\",e.BG_BLACK=\"bgBlack\",e.BG_BRIGHT_RED=\"bgBrightRed\",e.BG_BRIGHT_GREEN=\"bgBrightGreen\",e.BG_BRIGHT_YELLOW=\"bgBrightYellow\",e.BG_BRIGHT_BLUE=\"bgBrightBlue\",e.BG_BRIGHT_MAGENTA=\"bgBrightMagenta\",e.BG_BRIGHT_CYAN=\"bgBrightCyan\",e.BG_BRIGHT_WHITE=\"bgBrightWhite\",e))(e||{});const t={reset:[0,\"000000\"],black:[30,\"1f2937\"],red:[31,\"dc2626\"],green:[32,\"2d6a4f\"],yellow:[33,\"92400e\"],blue:[34,\"1a56db\"],magenta:[35,\"6d28d9\"],cyan:[36,\"0e7490\"],white:[37,\"374151\"],gray:[90,\"6b7280\"],brightRed:[91,\"ef4444\"],brightGreen:[92,\"059669\"],brightYellow:[93,\"d97706\"],brightBlue:[94,\"3b82f6\"],brightMagenta:[95,\"8b5cf6\"],brightCyan:[96,\"06b6d4\"],brightWhite:[97,\"f9fafb\"],bgBlack:[40,\"111827\"],bgRed:[41,\"fca5a5\"],bgGreen:[42,\"a7f3d0\"],bgYellow:[43,\"fde68a\"],bgBlue:[44,\"bfdbfe\"],bgMagenta:[45,\"ddd6fe\"],bgCyan:[46,\"a5f3fc\"],bgWhite:[47,\"f9fafb\"],bgGray:[100,\"d1d5db\"],bgBrightRed:[101,\"fee2e2\"],bgBrightGreen:[102,\"d1fae5\"],bgBrightYellow:[103,\"fef3c7\"],bgBrightBlue:[104,\"dbeafe\"],bgBrightMagenta:[105,\"ede9fe\"],bgBrightCyan:[106,\"cffafe\"],bgBrightWhite:[107,\"ffffff\"]};function r(e=\"ansi\"){const r={};for(const[n,[o,i]]of Object.entries(t))r[n]=\"html\"===e?\"reset\"===n?\"</span>\":`<span style=\"color:#${i}\">`:\"\u001b[\"+o+\"m\";return r}function n(e,t=\"ansi\"){const n=r(t);return\"string\"==typeof e?n.yellow:\"number\"==typeof e?n.cyan:\"boolean\"==typeof e?n.magenta:\"function\"==typeof e?n.red:null===e?n.gray:Array.isArray(e)?n.blue:\"object\"==typeof e?n.green:n.white}function o(e){return\"string\"==typeof e?'\"\"':\"number\"==typeof e?\"number\":\"boolean\"==typeof e?\"bool\":\"function\"==typeof e?\"function\":null===e?\"null\":Array.isArray(e)?e.length?\"[\"+o(e[0])+\"]\":\"[]\":\"object\"==typeof e?\"{...}\":typeof e}function i(e,t=0,l=\"ansi\"){const g=r(l),a=\"html\"===l,s=\" \".repeat(t);if(\"object\"!=typeof e||null===e){return n(e,l)+o(e)+g.reset}if(Array.isArray(e)){if(a){let r=[];e.length&&(r=e.every(t=>typeof t==typeof e[0])?[i(e[0],t+1,l)]:e.map(e=>i(e,t+1,l)));return`<details open><summary style=\"cursor:pointer;display:inline\">${`${g.blue}[${g.reset} ${e.length} × ${o(e[0]??void 0)} ${g.blue}]${g.reset}`}</summary>${r.map(e=>`<div style=\"margin-left:1.5em\">${e}</div>`).join(\"\")}</details>`}let r=g.blue+\"[\"+g.reset;return e.length&&(r+=\"\\n\"),e.every(t=>typeof t==typeof e[0])?r+=s+\" \"+i(e[0],t+1,l)+\",\\n\":e.forEach((n,o)=>{r+=s+\" \"+i(n,t+1,l),o<e.length-1&&(r+=\",\"),r+=\"\\n\"}),r+=s+g.blue+\"]\"+g.reset,r}const b=Object.keys(e);if(a){const r=b.slice(0,4).join(\", \")+(b.length>4?\"…\":\"\");return`<details open><summary style=\"cursor:pointer\">${`${g.green}{${g.reset} ${r} ${g.green}}${g.reset}`}</summary>${b.map(r=>{const a=e[r],s=n(a,l);return\"object\"==typeof a&&null!==a?`<div style=\"margin-left:1.5em\">${s}${r}${g.reset}: ${i(a,t+1,l)}</div>`:`<div style=\"margin-left:1.5em\">${s}${r}: ${o(a)}${g.reset}</div>`}).join(\"\")}</details>`}let f=g.green+\"{\"+g.reset;return b.length&&(f+=\"\\n\"),b.forEach((r,a)=>{const y=e[r],c=n(y,l);f+=s+\" \",f+=\"object\"==typeof y&&null!==y?c+r+g.reset+\": \"+i(y,t+1,l):c+r+\": \"+o(y)+g.reset,a<b.length-1&&(f+=\",\"),f+=\"\\n\"}),f+=s+g.green+\"}\"+g.reset,f}function l(e=\"\",t={}){let{color:n,style:o=\"color:rgb(54, 165, 220); font-size: 10pt;\",hideInProduction:l,startSpinner:g=!1,stopSpinner:a=!1}=t;const s=r();void 0===l&&(l=\"undefined\"!=typeof window&&window?.location.hostname.includes(\"localhost\")),\"object\"==typeof e&&(e=i(e)+\"\\n\\n\"+JSON.stringify(e,null,2)),Array.isArray(n)&&1==n.length&&(n=n[0]),n&&\"undefined\"!=typeof process&&(\"string\"==typeof e&&e.includes(\"%c\")&&Array.isArray(n)?e=e.replace(/%c/g,(e,t)=>s[n[t]]||\"\"):n&&\"string\"==typeof n&&(e=(s[n]||\"\")+e+s.reset));var b=0;return g?globalThis.interval=setInterval(()=>{process.stdout.write((Array.isArray(n)?s[n[0]]:s[n]||\"\")+\"\\r\"+\"⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏\".split(\"\")[b=++b%10]+\" \"+e+s.reset)},50):a?(clearInterval(globalThis.interval),process.stdout.write(\"\\r\"+(e||\" \")+\" \".repeat(\"string\"==typeof e?e.length+20:40)+\"\\n\")):\"string\"==typeof o?(1==o.split(\" \").length||n?o=`color: ${n||o}; font-size: 11pt;`:o.match(/^#[0-9a-fA-F]{6}$/)&&(o=`color: ${o}; font-size: 11pt;`),l?console.debug((o?\"%c\":\"\")+(e||\"\"),o):console.log((o?\"%c\":\"\")+(e||\"\"),o)):\"object\"==typeof o&&console.log(e,...o),!0}export{e as ColorName,r as getColors,l as log,i as printJSONStructure};\n//# sourceMappingURL=log.es.js.map\n","import{printJSONStructure as e,log as t}from\"./log.es.js\";const n=async(e,t)=>{let n;return async function(...o){clearTimeout(n),n=setTimeout(async()=>{clearTimeout(n),await e(...o)},t)}},o=e=>new Promise(t=>setTimeout(t,1e3*e||0)),r=(e,t)=>{let n=e=>t?.startsWith(e)||!1,o=e,r=t;return t?.startsWith(\"http:\")||t?.startsWith(\"https:\")?o=\"\":n(\"/\")||o.endsWith(\"/\")?n(\"/\")&&o.endsWith(\"/\")&&(r=t.slice(1)):r=\"/\"+t,{baseURL:o,path:r}};function s(e){if(\"undefined\"==typeof document)return;let t,n=document.getElementById(\"alert-overlay\");if(!n){n=document.body.appendChild(document.createElement(\"div\")),n.id=\"alert-overlay\",n.setAttribute(\"style\",\"position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center\"),n.innerHTML='<div id=\"alert-box\" style=\"background:#fff;padding:1.5em 2em;border-radius:8px;box-shadow:0 2px 16px #0003;min-width:320px;max-width:90vw;max-height:80vh;position:relative;display:flex;flex-direction:column;\">\\n <button id=\"close-alert\" style=\"position:absolute;top:12px;right:20px;font-size:1.5em;background:none;border:none;cursor:pointer;color:black;\">×</button>\\n <div id=\"alert-list\" style=\"overflow:auto;flex:1;font-family:monospace;font-size:13px;\"></div>\\n </div>',n.addEventListener(\"click\",e=>e.target==n&&n.remove());const e=document.getElementById(\"close-alert\");e&&(e.onclick=()=>n.remove())}t=document.getElementById(\"alert-list\"),t.innerHTML+=`<div style=\"border-bottom:1px solid #e5e7eb;margin:0.5em 0;padding-bottom:0.5em\">${e}</div>`}function i(e){return e.replace(/&/g,\"&\").replace(/</g,\"<\").replace(/>/g,\">\")}function a(){\"undefined\"!=typeof document&&document.addEventListener(\"keydown\",t=>{const n=window.grab;if(n&&n.log&&\"i\"===t.key&&t.ctrlKey&&t.altKey){let t=\"\";for(const o of n.log){const n=new Date(o.lastFetchTime).toLocaleString(),r=e(o.request,0,\"html\"),s=e(o.response,0,\"html\"),a=i(JSON.stringify(o.response,null,2));t+=`\\n <details open style=\"margin-bottom:0.75em\">\\n <summary style=\"cursor:pointer;font-weight:bold;padding:4px 0;list-style:none;display:flex;justify-content:space-between\">\\n <span style=\"color:#1a56db\">${i(o.path)}</span>\\n <span style=\"color:#6b7280;font-weight:normal;margin-left:1em\">${n}</span>\\n </summary>\\n <div style=\"padding-left:1em;margin-top:0.5em\">\\n <details style=\"margin-bottom:0.4em\">\\n <summary style=\"cursor:pointer;color:#6b7280;font-size:0.9em\">Request</summary>\\n <div style=\"padding:0.4em 0 0 1em\">${r}</div>\\n </details>\\n <details open style=\"margin-bottom:0.4em\">\\n <summary style=\"cursor:pointer;color:#6b7280;font-size:0.9em\">Response (structure)</summary>\\n <div style=\"padding:0.4em 0 0 1em\">${s}</div>\\n </details>\\n <details style=\"margin-bottom:0.4em\">\\n <summary style=\"cursor:pointer;color:#6b7280;font-size:0.9em\">Response (data)</summary>\\n <pre style=\"margin:0.4em 0 0 1em;padding:0.5em;background:#f9fafb;border:1px solid #e5e7eb;border-radius:4px;overflow:auto;max-height:300px;font-size:12px\">${a}</pre>\\n </details>\\n </div>\\n </details>`}s(t||\"<em>No requests logged yet.</em>\")}})}function l(o){return async function i(a,l){const c=function(e){return{...\"undefined\"!=typeof window?window?.grab?.defaults:globalThis?.grab?.defaults||{},...e}}(l);let{headers:d,response:u,method:f=(c.post?\"POST\":c.put?\"PUT\":c.patch?\"PATCH\":\"GET\"),cache:p,timeout:m=30,baseURL:y=\"undefined\"!=typeof process&&process.env.SERVER_API_URL||\"/api/\",cancelOngoingIfNew:g,cancelNewIfOngoing:b,rateLimit:w,debug:h,infiniteScroll:v,logger:T=t,onRequest:x,onResponse:L,onError:E,onStream:A,unzip:S,dom:O,body:R,post:P,put:k,patch:$,...j}=c;const q=r(y,a);y=q.baseURL,a=q.path;const F=function(e){const t=\"function\"==typeof e?e:null;return{response:!e||t?{}:e,resFunction:t}}(u);let N=F.response,D=F.resFunction;const z=\"undefined\"!=typeof window?window.grab:globalThis.grab,I=z?.log||[];D?N=D({...N,isLoading:!0}):\"object\"==typeof N&&(N.isLoading=!0);try{const r=await async function(e,t,o,r){const{debounce:s=0,repeat:i=0,repeatEvery:a=null,setDefaults:l=!1}=o;if(s>0){const i=await n(async()=>{await r(e,{...t,debounce:0})},1e3*s);return await i(),o.response||{}}if(i>1){for(let n=0;n<i;n++)await r(e,{...t,repeat:0});return o.response||{}}if(a)return setInterval(async()=>{await r(e,{...t,repeat:0,repeatEvery:null})},1e3*a),o.response||{};if(l){const e=\"undefined\"!=typeof window?window.grab:globalThis.grab;return e&&(e.defaults={...t,setDefaults:void 0}),o.response||{}}return null}(a,l||{},c,i);if(r)return r;!function(e,t,n,o){if(\"undefined\"==typeof window)return;const{regrabOnStale:r,regrabOnFocus:s,regrabOnNetwork:i,cache:a,cacheForTime:l=60}=n,c=async()=>await o(e,{...t,cache:!1});r&&a&&setTimeout(c,1e3*l),i&&window.addEventListener(\"online\",c),s&&(window.addEventListener(\"focus\",c),document.addEventListener(\"visibilitychange\",async()=>{\"visible\"===document.visibilityState&&await c()}))}(a,l||{},c,i);let{params:s,priorRequest:u,response:E,paramsAsText:P}=function(e,t,n,o,r,s){const{cache:i,cacheForTime:a,infiniteScroll:l}=n,[c,d]=l||[],u=JSON.stringify(c?{...t,[c]:void 0}:t);let f=s.find(t=>t.request===u&&t.path===e);if(c){let e=(f?.currentPage||0)+1||t?.[c]||1;f?f.currentPage=e:(o[d]=[],e=1),t={...t,[c]:e}}else{for(let e of Object.keys(o))o[e]=void 0;if(i&&f?.response&&(!a||f.lastFetchTime>Date.now()-1e3*a)){for(let e of Object.keys(f.response))o[e]=f.response[e];r&&(o=r(o))}}return{params:t,priorRequest:f,response:o,paramsAsText:u}}(a,j,c,N,D,I);if(j=s,N=E,function(e,n,o,r,s){if(\"undefined\"==typeof window||!o?.length)return;const[i,,a]=o;if(void 0===a)return;let l=\"string\"==typeof a?document.querySelector(a):a;l?(window.scrollListener&&\"function\"==typeof l.removeEventListener&&l.removeEventListener(\"scroll\",window.scrollListener),window.scrollListener=t=>{const o=t.target;localStorage.setItem(\"scroll\",JSON.stringify([o.scrollTop,o.scrollLeft,a])),o.scrollHeight-o.scrollTop<=o.clientHeight+200&&s(e,{...n,cache:!1,[i]:(r?.currentPage||0)+1})},l.addEventListener(\"scroll\",window.scrollListener)):t(\"paginateDOM not found\",{color:\"red\"})}(a,l,v,u,i),w>0&&u?.lastFetchTime>Date.now()-1e3*w)throw new Error(`Fetch rate limit exceeded for ${a}. Wait ${w}s between requests.`);if(u?.controller)if(g)u.controller.abort();else if(b)return{isLoading:!0};const k=new AbortController;let $=k.signal;g||\"function\"!=typeof AbortSignal.timeout||($=AbortSignal.timeout(1e3*m)),I.unshift({path:a,request:P,lastFetchTime:Date.now(),controller:k});let{fetchParams:q,paramsGETRequest:F}=function(e,t,n,o,r,s){const i=[\"POST\",\"PUT\",\"PATCH\"].includes(e),a={method:e,headers:{\"Content-Type\":\"application/json\",Accept:\"application/json\",...t},body:n||(i?JSON.stringify(o):null),redirect:\"follow\",cache:r?\"force-cache\":\"no-store\",signal:s};let l=\"\";return i||(l=(Object.keys(o).length?\"?\":\"\")+new URLSearchParams(o).toString()),{fetchParams:a,paramsGETRequest:l}}(f,d,R,j,!!p,$);if(\"function\"==typeof x){const e=x(a,N,j,q);Array.isArray(e)&&([a,N,j,q]=e)}const z=/* @__PURE__ */new Date,U=await o(y,a,F,q,j,A,S,O);if(D?N=D({...N,isLoading:void 0}):\"object\"==typeof N&&delete N.isLoading,\"function\"==typeof L){const e=L(a,N,j,q);Array.isArray(e)&&([a,N,j,q]=e)}const H=((Number(/* @__PURE__ */new Date)-Number(z))/1e3).toFixed(1);h&&T(`Path:${y+a+F}\\n${JSON.stringify(l,null,2)}\\nTime: ${H}s\\nResponse: ${e(U)}`);const[,W]=v||[];return N=function(e,t,n,o){if(\"object\"==typeof e&&null!==e){for(let n of Object.keys(e))t[n]=o===n&&Array.isArray(t[n])?[...t[n],...e[n]]:e[n];t.data=e}else n?t=n({data:e,...e}):\"object\"==typeof t&&(t.data=e);return t}(U,N,D,W),I[0]&&(I[0].response=N),D&&(N=D(N)),N}catch(U){if(\"function\"==typeof E&&E(U.message,y+a,j),c.retryAttempts&&c.retryAttempts>0)return await i(a,{...l,retryAttempts:--c.retryAttempts});!U.message.includes(\"signal\")&&h&&(T(`Error: ${U.message}\\nPath:${y+a}\\n`,{color:\"red\"}),\"undefined\"!=typeof document&&s(U.message)),N=N||{},N.error=U.message;const e=\"function\"==typeof u?u:null;return e?(N.data=e({isLoading:void 0,error:U.message}),N=N.data):delete N.isLoading,N}}}export{s as a,r as b,l as c,n as d,a as s,o as w};\n//# sourceMappingURL=core-BX1uvK6L.js.map\n","import{w as t,s as r,c as o}from\"./core-BX1uvK6L.js\";import{b as e,d as n,a}from\"./core-BX1uvK6L.js\";import{log as s}from\"./log.es.js\";async function i(t){const{extract:r}=await import(\"./archiver-web.es.js\"),o=await r({archiveBuffer:t}),e={};for(const n of o)e[n.path]=n.content;return e}async function c(t,r){const{parseHTML:o}=await import(\"./index-CLlAnStL.js\"),{document:e}=o(t);if(!r||!0===r)return e;const n=e.querySelector(r);return n?n.innerHTML??n.textContent:null}const l=o(async function(r,o,e,n,a,s,l,d){const p=\"undefined\"!=typeof window?window.grab:globalThis.grab,u=p?.mock?.[o],f=JSON.stringify(a);if(u&&(!u.method||u.method===n.method)&&(!u.params||f===JSON.stringify(u.params)))return await t(u.delay||0),\"function\"==typeof u.response?u.response(a):u.response;const w=await fetch(r+o+e,n).catch(t=>{throw new Error(t.message)});if(!w.ok)throw new Error(`HTTP error: ${w.status} ${w.statusText}`);if(s)return await s(w.body),null;const h=w.headers.get(\"content-type\")??\"\",g=!1!==l&&(h.includes(\"application/zip\")||h.includes(\"application/x-zip\")),m=!1!==d&&(\"string\"==typeof d||h.includes(\"text/html\"));if(g){const t=await w.arrayBuffer().catch(t=>{throw new Error(\"Error reading zip: \"+t)});return{data:await i(t)}}if(m){const t=await w.text().catch(t=>{throw new Error(\"Error reading html: \"+t)});return{data:await c(t,\"string\"!=typeof d||d)}}return await(h.includes(\"application/json\")?w.json():h.includes(\"application/pdf\")||h.includes(\"application/octet-stream\")?w.blob():h?w.text():w.json()).catch(t=>{throw new Error(\"Error parsing response: \"+t)})}),d=l;d.instance=(t={})=>(r,o={})=>l(r,{...t,...o}),d.log=[],d.mock={},d.defaults={},\"undefined\"!=typeof window?(window.log=s,window.grab=d,r(),document.addEventListener(\"DOMContentLoaded\",()=>{try{const t=localStorage.getItem(\"scroll\");if(!t)return;const[r,o,e]=JSON.parse(t);if(!r||!e)return;const n=document.querySelector(e);n&&(n.scrollTop=r,n.scrollLeft=o)}catch(t){console.warn(\"Failed to restore scroll position\",t)}})):\"undefined\"!=typeof globalThis&&(globalThis.log=s,globalThis.grab=d);export{e as buildUrl,n as debouncer,d as default,d as grab,s as log,r as setupDevTools,a as showAlert,t as wait};\n//# sourceMappingURL=grab-api.es.js.map\n","/**\r\n * @fileoverview HTTP client implementation using grab-url\r\n */\r\n\r\nimport grab from 'grab-url';\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\nimport { HttpClient, RequestsProxyConfigDict } from '../types';\r\n\r\n/**\r\n * Simple HTTP client implementation using grab-url with proxy support.\r\n * This client handles HTTP/HTTPS requests with configurable headers and proxy settings.\r\n *\r\n * @internal\r\n */\r\nexport class FetchHttpClient implements HttpClient {\r\n private requestHeaders: Record<string, string> = {};\r\n private proxyConfiguration: Partial<RequestsProxyConfigDict> = {};\r\n\r\n /**\r\n * Creates a new FetchHttpClient instance.\r\n * Sets default Accept-Language header to English.\r\n */\r\n constructor() {\r\n this.requestHeaders['Accept-Language'] = 'en-US';\r\n }\r\n\r\n /**\r\n * Sets a custom header for all requests.\r\n *\r\n * @param {string} headerName - The header name\r\n * @param {string} headerValue - The header value\r\n */\r\n setHeader(headerName: string, headerValue: string): void {\r\n this.requestHeaders[headerName] = headerValue;\r\n }\r\n\r\n /**\r\n * Configures proxy settings for all requests.\r\n *\r\n * @param {RequestsProxyConfigDict} proxies - Proxy configuration dictionary\r\n */\r\n setProxies(proxies: RequestsProxyConfigDict): void {\r\n this.proxyConfiguration = proxies;\r\n }\r\n\r\n /**\r\n * Performs an HTTP GET request.\r\n *\r\n * @param {string} url - The URL to request\r\n * @param {RequestInit} [options] - Additional request options\r\n * @returns {Promise<Response>} The HTTP response\r\n */\r\n async get(url: string, options?: RequestInit): Promise<Response> {\r\n const proxyAgent = this.getProxyAgentForUrl(url);\r\n return grab(url, {\r\n ...options,\r\n method: 'GET',\r\n headers: { ...this.requestHeaders, ...(options?.headers as Record<string, string>) },\r\n agent: proxyAgent\r\n } as any);\r\n }\r\n\r\n /**\r\n * Performs an HTTP POST request.\r\n *\r\n * @param {string} url - The URL to request\r\n * @param {RequestInit} [options] - Additional request options\r\n * @returns {Promise<Response>} The HTTP response\r\n */\r\n async post(url: string, options?: RequestInit): Promise<Response> {\r\n const proxyAgent = this.getProxyAgentForUrl(url);\r\n return grab(url, {\r\n ...options,\r\n method: 'POST',\r\n headers: { ...this.requestHeaders, ...(options?.headers as Record<string, string>) },\r\n agent: proxyAgent\r\n } as any);\r\n }\r\n\r\n /**\r\n * Gets the appropriate proxy agent for a given URL.\r\n *\r\n * @private\r\n * @param {string} url - The URL being requested\r\n * @returns {any} The proxy agent or undefined if no proxy is configured\r\n */\r\n private getProxyAgentForUrl(url: string): any {\r\n if (Object.keys(this.proxyConfiguration).length === 0) {\r\n return undefined;\r\n }\r\n\r\n const proxyUrl = url.startsWith('https://')\r\n ? this.proxyConfiguration.https\r\n : this.proxyConfiguration.http;\r\n\r\n if (!proxyUrl) {\r\n return undefined;\r\n }\r\n\r\n return new HttpsProxyAgent(proxyUrl);\r\n }\r\n}\r\n","/**\r\n * @fileoverview Main API class for the YouTube Transcript API\r\n */\r\n\r\nimport { ProxyConfig } from './proxies';\r\nimport { FetchedTranscript, TranscriptList } from './models';\r\nimport { TranscriptListFetcher } from './fetchers/transcript-list-fetcher';\r\nimport { HttpClient } from './types';\r\nimport { FetchHttpClient } from './http/fetch-http-client';\r\n\r\n/**\r\n * Main API class for retrieving YouTube transcripts.\r\n * This is the primary entry point for the library.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Basic usage\r\n * const api = new YouTubeTranscriptApi();\r\n * const transcript = await api.fetchTranscript('video_id');\r\n *\r\n * // With language preference\r\n * const transcript = await api.fetchTranscript('video_id', { languages: ['de', 'en'] });\r\n *\r\n * // With proxy\r\n * import { GenericProxyConfig } from 'youtube-transcript-api';\r\n * const api = new YouTubeTranscriptApi({\r\n * proxyConfig: new GenericProxyConfig({\r\n * httpUrl: 'http://user:pass@proxy.example.com:8080'\r\n * })\r\n * });\r\n * ```\r\n */\r\nexport class YouTubeTranscriptApi {\r\n private transcriptListFetcher: TranscriptListFetcher;\r\n\r\n /**\r\n * Creates a new YouTubeTranscriptApi instance.\r\n *\r\n * Note on thread-safety: As this class initializes an HTTP client,\r\n * it is not thread-safe. Make sure to initialize an instance per\r\n * thread if used in a multi-threading scenario!\r\n *\r\n * @param {Object} [options] - Configuration options\r\n * @param {ProxyConfig} [options.proxyConfig] - An optional ProxyConfig object defining proxies\r\n * used for all network requests. This can be used to work around your IP being blocked\r\n * by YouTube, as described in the \"Working around IP bans\" section of the README.\r\n * @param {HttpClient} [options.httpClient] - You can optionally pass in a custom HTTP client\r\n * if you want to share state between different instances of YouTubeTranscriptApi or\r\n * customize request behavior.\r\n *\r\n * @example\r\n * ```typescript\r\n * // Basic usage\r\n * const api = new YouTubeTranscriptApi();\r\n *\r\n * // With Webshare proxy\r\n * import { WebshareProxyConfig } from 'youtube-transcript-api';\r\n * const api = new YouTubeTranscriptApi({\r\n * proxyConfig: new WebshareProxyConfig({\r\n * proxyUsername: 'your-username',\r\n * proxyPassword: 'your-password',\r\n * filterIpLocations: ['us', 'de']\r\n * })\r\n * });\r\n *\r\n * // With generic proxy\r\n * import { GenericProxyConfig } from 'youtube-transcript-api';\r\n * const api = new YouTubeTranscriptApi({\r\n * proxyConfig: new GenericProxyConfig({\r\n * httpUrl: 'http://user:pass@proxy.example.com:8080',\r\n * httpsUrl: 'https://user:pass@proxy.example.com:8080'\r\n * })\r\n * });\r\n * ```\r\n */\r\n constructor(options?: { proxyConfig?: ProxyConfig; httpClient?: HttpClient }) {\r\n const httpClient = this.initializeHttpClient(options);\r\n this.configureHttpClientWithProxy(httpClient, options?.proxyConfig);\r\n this.transcriptListFetcher = new TranscriptListFetcher(httpClient, options?.proxyConfig || null);\r\n }\r\n\r\n /**\r\n * Initializes the HTTP client from options or creates a default one.\r\n *\r\n * @private\r\n * @param {Object} [options] - Configuration options\r\n * @returns {HttpClient} The initialized HTTP client\r\n */\r\n private initializeHttpClient(options?: { httpClient?: HttpClient }): HttpClient {\r\n return options?.httpClient || new FetchHttpClient();\r\n }\r\n\r\n /**\r\n * Configures the HTTP client with proxy settings if provided.\r\n *\r\n * @private\r\n * @param {HttpClient} httpClient - The HTTP client to configure\r\n * @param {ProxyConfig} [proxyConfig] - Optional proxy configuration\r\n */\r\n private configureHttpClientWithProxy(httpClient: HttpClient, proxyConfig?: ProxyConfig): void {\r\n if (!proxyConfig || !(httpClient instanceof FetchHttpClient)) {\r\n return;\r\n }\r\n\r\n const proxyDictionary = proxyConfig.toRequestsDict();\r\n httpClient.setProxies(proxyDictionary);\r\n\r\n if (proxyConfig.preventKeepingConnectionsAlive) {\r\n httpClient.setHeader('Connection', 'close');\r\n }\r\n\r\n // Note: Retry logic for 429 status codes with configured retries\r\n // would need to be implemented in the HTTP client or fetcher\r\n }\r\n\r\n /**\r\n * Retrieves the transcript for a single video.\r\n * This is a shortcut for calling:\r\n * `api.listTranscripts(videoId).then(list => list.findTranscript(languages)).then(t => t.fetch())`\r\n *\r\n * @param {string} videoId - The ID of the video you want to retrieve the transcript for.\r\n * Make sure that this is the actual ID, NOT the full URL to the video!\r\n * @param {Object} [options] - Fetch options\r\n * @param {string[]} [options.languages=['en']] - A list of language codes in descending priority.\r\n * For example, if this is set to ['de', 'en'] it will first try to fetch the german\r\n * transcript (de) and then fetch the english transcript (en) if it fails to do so.\r\n * @param {boolean} [options.preserveFormatting=false] - Whether to keep select HTML text formatting\r\n * @returns {Promise<FetchedTranscript>} The fetched transcript\r\n *\r\n * @example\r\n * ```typescript\r\n * const api = new YouTubeTranscriptApi();\r\n *\r\n * // Fetch English transcript\r\n * const transcript = await api.fetchTranscript('dQw4w9WgXcQ');\r\n *\r\n * // Fetch with language preference\r\n * const transcript = await api.fetchTranscript('dQw4w9WgXcQ', {\r\n * languages: ['de', 'en']\r\n * });\r\n *\r\n * // Preserve HTML formatting\r\n * const transcript = await api.fetchTranscript('dQw4w9WgXcQ', {\r\n * preserveFormatting: true\r\n * });\r\n *\r\n * // Iterate over snippets\r\n * for (const snippet of transcript) {\r\n * console.log(`${snippet.start}s: ${snippet.text}`);\r\n * }\r\n * ```\r\n */\r\n async fetchTranscript(\r\n videoId: string,\r\n options?: {\r\n languages?: string[];\r\n preserveFormatting?: boolean;\r\n }\r\n ): Promise<FetchedTranscript> {\r\n const preferredLanguages = options?.languages || ['en'];\r\n const preserveFormatting = options?.preserveFormatting || false;\r\n\r\n const transcriptList = await this.listTranscripts(videoId);\r\n const transcript = transcriptList.findTranscript(preferredLanguages);\r\n return transcript.fetch(preserveFormatting);\r\n }\r\n\r\n /**\r\n * Retrieves the list of transcripts which are available for a given video.\r\n * It returns a TranscriptList object which is iterable and provides methods to\r\n * filter the list of transcripts for specific languages.\r\n *\r\n * While iterating over the TranscriptList, the individual transcripts are\r\n * represented by Transcript objects, which provide metadata and can either\r\n * be fetched by calling transcript.fetch() or translated by calling\r\n * transcript.translate('en').\r\n *\r\n * @param {string} videoId - The ID of the video you want to retrieve the transcript for.\r\n * Make sure that this is the actual ID, NOT the full URL to the video!\r\n * @returns {Promise<TranscriptList>} A list of available transcripts\r\n *\r\n * @example\r\n * ```typescript\r\n * const api = new YouTubeTranscriptApi();\r\n *\r\n * // Retrieve available transcripts\r\n * const transcriptList = await api.listTranscripts('video_id');\r\n *\r\n * // Iterate over all available transcripts\r\n * for (const transcript of transcriptList) {\r\n * console.log(\r\n * transcript.videoId,\r\n * transcript.language,\r\n * transcript.languageCode,\r\n * transcript.isGenerated,\r\n * transcript.isTranslatable,\r\n * transcript.translationLanguages\r\n * );\r\n *\r\n * // Fetch the actual transcript data\r\n * const fetched = await transcript.fetch();\r\n * console.log(fetched);\r\n *\r\n * // Translate the transcript\r\n * if (transcript.isTranslatable) {\r\n * const translated = transcript.translate('de');\r\n * const fetchedTranslated = await translated.fetch();\r\n * console.log(fetchedTranslated);\r\n * }\r\n * }\r\n *\r\n * // Filter for specific language\r\n * const transcript = transcriptList.findTranscript(['de', 'en']);\r\n *\r\n * // Filter for manually created transcripts\r\n * const manual = transcriptList.findManuallyCreatedTranscript(['de', 'en']);\r\n *\r\n * // Filter for automatically generated transcripts\r\n * const generated = transcriptList.findGeneratedTranscript(['de', 'en']);\r\n * ```\r\n */\r\n async listTranscripts(videoId: string): Promise<TranscriptList> {\r\n return this.transcriptListFetcher.fetchTranscriptList(videoId);\r\n }\r\n\r\n /**\r\n * Alias for fetchTranscript() for backward compatibility.\r\n *\r\n * @deprecated Use fetchTranscript() instead\r\n * @param {string} videoId - The video ID\r\n * @param {Object} [options] - Fetch options\r\n * @returns {Promise<FetchedTranscript>} The fetched transcript\r\n */\r\n async fetch(\r\n videoId: string,\r\n options?: {\r\n languages?: string[];\r\n preserveFormatting?: boolean;\r\n }\r\n ): Promise<FetchedTranscript> {\r\n return this.fetchTranscript(videoId, options);\r\n }\r\n\r\n /**\r\n * Alias for listTranscripts() for backward compatibility.\r\n *\r\n * @deprecated Use listTranscripts() instead\r\n * @param {string} videoId - The video ID\r\n * @returns {Promise<TranscriptList>} A list of available transcripts\r\n */\r\n async list(videoId: string): Promise<TranscriptList> {\r\n return this.listTranscripts(videoId);\r\n }\r\n}\r\n","/**\r\n * @fileoverview Transcript timing utilities: encode/decode run-length compressed\r\n * playback speeds and interpolate timestamps from character offsets.\r\n */\r\n\r\nimport { FetchedTranscript } from '../models';\r\n\r\n/**\r\n * Encodes speech speed from a fetched transcript into a compact run-length string.\r\n * Optionally prepends a YouTube embed iframe with data-timestamps for player sync.\r\n * @param transcript - A FetchedTranscript returned by fetchTranscript()\r\n * @param addPlayer - If true, prepends an iframe embed with data-timestamps attribute\r\n * @returns html content, word count, run-length encoded speed string, and raw timestamps\r\n */\r\nexport function encodeTranscriptSpeeds(\r\n transcript: FetchedTranscript,\r\n addPlayer = false\r\n): {\r\n html: string;\r\n word_count: number;\r\n speeds: string;\r\n} {\r\n let charCount = 0;\r\n const timestamps: [number, number][] = [];\r\n const textParts: string[] = [];\r\n\r\n for (const snippet of transcript.snippets) {\r\n textParts.push(snippet.text);\r\n charCount += snippet.text.length;\r\n if (snippet.start > 0) {\r\n timestamps.push([charCount, snippet.start]);\r\n }\r\n }\r\n\r\n const content = textParts.join(' ').replace(/\\s+/g, ' ');\r\n const word_count = content.split(/\\s+/).filter(Boolean).length;\r\n\r\n const speedValues = timestamps.map(([char, time]) => Math.floor(char / time) - 10);\r\n if (speedValues.length === 0) {\r\n return { html: content, word_count, speeds: '' };\r\n }\r\n\r\n const compressed: number[] = [];\r\n const compressedCount: number[] = [];\r\n let currentNum = speedValues[0];\r\n let count = 1;\r\n\r\n for (let i = 1; i < speedValues.length; i++) {\r\n if (speedValues[i] === currentNum) {\r\n count++;\r\n } else {\r\n compressed.push(currentNum);\r\n compressedCount.push(count);\r\n currentNum = speedValues[i];\r\n count = 1;\r\n }\r\n }\r\n compressed.push(currentNum);\r\n compressedCount.push(count);\r\n\r\n const speeds = compressed.map((val, i) => `${val}x${compressedCount[i]}`).join(',');\r\n\r\n const html = addPlayer\r\n ? `<iframe width=\"100%\" height=\"315px\" data-timestamps=\"${speeds}\" ` +\r\n `src=\"https://www.youtube.com/embed/${transcript.videoId}\" frameborder=\"0\" ` +\r\n `allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; ` +\r\n `gyroscope; picture-in-picture\" allowfullscreen></iframe>${content}`\r\n : content;\r\n\r\n return { html, word_count, speeds };\r\n}\r\n\r\n/**\r\n * Given a character index in the joined transcript text, returns the interpolated\r\n * video timestamp in seconds. Uses the nearest snippet boundaries to interpolate.\r\n */\r\nexport function getTimestampAtChar(transcript: FetchedTranscript, charIndex: number): number {\r\n let charCount = 0;\r\n const points: [number, number][] = [[0, 0]]; // [cumulativeChars, seconds]\r\n\r\n for (const snippet of transcript.snippets) {\r\n charCount += snippet.text.length + 1; // +1 for the join space\r\n points.push([charCount, snippet.start]);\r\n }\r\n\r\n if (charIndex <= 0) return 0;\r\n if (charIndex >= points[points.length - 1][0]) return points[points.length - 1][1];\r\n\r\n for (let i = 1; i < points.length; i++) {\r\n if (points[i][0] >= charIndex) {\r\n const [c0, t0] = points[i - 1];\r\n const [c1, t1] = points[i];\r\n const ratio = (charIndex - c0) / (c1 - c0);\r\n return t0 + ratio * (t1 - t0);\r\n }\r\n }\r\n\r\n return points[points.length - 1][1];\r\n}\r\n\r\n/**\r\n * Decompresses a speeds string produced by encodeTranscriptSpeeds back into a flat array.\r\n * Format: \"12x3,8x7,15x1\" → [12,12,12, 8,8,8,8,8,8,8, 15]\r\n */\r\nexport function decompressTimestampsArray(speeds: string): number[] {\r\n const decompressed: number[] = [];\r\n for (const part of speeds.split(',')) {\r\n const [num, count] = part.split('x');\r\n decompressed.push(...Array(parseInt(count)).fill(parseInt(num)));\r\n }\r\n return decompressed;\r\n}\r\n","/**\r\n * @fileoverview Proxy configuration classes for the YouTube Transcript API\r\n */\r\n\r\nimport { RequestsProxyConfigDict } from '../types';\r\n\r\n/**\r\n * Exception for invalid proxy configurations\r\n */\r\nexport class InvalidProxyConfig extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'InvalidProxyConfig';\r\n Object.setPrototypeOf(this, InvalidProxyConfig.prototype);\r\n }\r\n}\r\n\r\n/**\r\n * Base class for all proxy configurations.\r\n * Any proxy config can be used as long as it can be converted to a RequestsProxyConfigDict.\r\n */\r\nexport abstract class ProxyConfig {\r\n /**\r\n * Converts this proxy config to a dictionary that can be used by HTTP clients.\r\n * @returns {RequestsProxyConfigDict} The proxy configuration dictionary\r\n */\r\n abstract toRequestsDict(): RequestsProxyConfigDict;\r\n\r\n /**\r\n * If you are using rotating proxies, it can be useful to prevent the HTTP\r\n * client from keeping TCP connections alive, as your IP won't be rotated on\r\n * every request if your connection stays open.\r\n * @returns {boolean} Whether to prevent keeping connections alive\r\n */\r\n get preventKeepingConnectionsAlive(): boolean {\r\n return false;\r\n }\r\n\r\n /**\r\n * Defines how many times we should retry if a request is blocked. When using\r\n * rotating residential proxies with a large IP pool it can make sense to retry a\r\n * couple of times when a blocked IP is encountered, since a retry will trigger\r\n * an IP rotation and the next IP might not be blocked.\r\n * @returns {number} Number of retries when blocked\r\n */\r\n get retriesWhenBlocked(): number {\r\n return 0;\r\n }\r\n}\r\n\r\n/**\r\n * Generic proxy configuration that can be used to set up any HTTP/HTTPS/SOCKS proxy.\r\n *\r\n * If only an HTTP or an HTTPS proxy is provided, it will be used for both types of\r\n * connections. However, you will have to provide at least one of the two.\r\n *\r\n * @example\r\n * ```typescript\r\n * const proxyConfig = new GenericProxyConfig({\r\n * httpUrl: 'http://user:pass@proxy.example.com:8080',\r\n * httpsUrl: 'https://user:pass@proxy.example.com:8080'\r\n * });\r\n * ```\r\n */\r\nexport class GenericProxyConfig extends ProxyConfig {\r\n protected _httpUrl: string | null;\r\n protected _httpsUrl: string | null;\r\n\r\n /**\r\n * Creates a generic proxy configuration.\r\n * If only an HTTP or an HTTPS proxy is provided, it will be used for both types of\r\n * connections. However, you will have to provide at least one of the two.\r\n *\r\n * @param {Object} options - Proxy configuration options\r\n * @param {string} [options.httpUrl] - The proxy URL used for HTTP requests. Defaults to httpsUrl if not provided.\r\n * @param {string} [options.httpsUrl] - The proxy URL used for HTTPS requests. Defaults to httpUrl if not provided.\r\n * @throws {InvalidProxyConfig} If neither httpUrl nor httpsUrl is provided\r\n */\r\n constructor(options: { httpUrl?: string; httpsUrl?: string }) {\r\n super();\r\n const { httpUrl, httpsUrl } = options;\r\n\r\n if (!httpUrl && !httpsUrl) {\r\n throw new InvalidProxyConfig(\r\n 'GenericProxyConfig requires you to define at least one of the two: http or https'\r\n );\r\n }\r\n\r\n this._httpUrl = httpUrl || null;\r\n this._httpsUrl = httpsUrl || null;\r\n }\r\n\r\n get httpUrl(): string | null {\r\n return this._httpUrl;\r\n }\r\n\r\n get httpsUrl(): string | null {\r\n return this._httpsUrl;\r\n }\r\n\r\n toRequestsDict(): RequestsProxyConfigDict {\r\n return {\r\n http: this.httpUrl || this.httpsUrl!,\r\n https: this.httpsUrl || this.httpUrl!\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Webshare proxy configuration for rotating residential proxies.\r\n *\r\n * Webshare is a provider offering rotating residential proxies, which is the\r\n * most reliable way to work around being blocked by YouTube.\r\n *\r\n * If you don't have a Webshare account yet, you will have to create one\r\n * at https://www.webshare.io/?referral_code=w0xno53eb50g and purchase a \"Residential\"\r\n * proxy package that suits your workload (make sure NOT to purchase \"Proxy Server\"\r\n * or \"Static Residential\"!).\r\n *\r\n * Once you have created an account you only need the \"Proxy Username\" and\r\n * \"Proxy Password\" that you can find in your Webshare settings to set up this config.\r\n *\r\n * @example\r\n * ```typescript\r\n * const proxyConfig = new WebshareProxyConfig({\r\n * proxyUsername: 'your-username',\r\n * proxyPassword: 'your-password',\r\n * filterIpLocations: ['us', 'de']\r\n * });\r\n * ```\r\n */\r\nexport class WebshareProxyConfig extends GenericProxyConfig {\r\n public static readonly DEFAULT_DOMAIN_NAME = 'p.webshare.io';\r\n public static readonly DEFAULT_PORT = 80;\r\n\r\n public readonly proxyUsername: string;\r\n public readonly proxyPassword: string;\r\n public readonly domainName: string;\r\n public readonly proxyPort: number;\r\n private readonly filterIpLocations: string[];\r\n private readonly _retriesWhenBlocked: number;\r\n\r\n /**\r\n * Creates a Webshare proxy configuration.\r\n *\r\n * Once you have created a Webshare account and purchased a \"Residential\" package\r\n * (make sure NOT to purchase \"Proxy Server\" or \"Static Residential\"!), this config\r\n * class allows you to easily use it by defaulting to the most reliable proxy settings\r\n * (rotating residential proxies).\r\n *\r\n * @param {Object} options - Webshare configuration options\r\n * @param {string} options.proxyUsername - \"Proxy Username\" found at https://dashboard.webshare.io/proxy/settings\r\n * @param {string} options.proxyPassword - \"Proxy Password\" found at https://dashboard.webshare.io/proxy/settings\r\n * @param {string[]} [options.filterIpLocations] - If you want to limit the pool of IPs to specific countries,\r\n * provide a list of location codes (e.g., ['us', 'de']). This can reduce latency and work around location-based restrictions.\r\n * @param {number} [options.retriesWhenBlocked=10] - How many times to retry if a request is blocked\r\n * @param {string} [options.domainName] - Custom domain name (defaults to p.webshare.io)\r\n * @param {number} [options.proxyPort] - Custom proxy port (defaults to 80)\r\n */\r\n constructor(options: {\r\n proxyUsername: string;\r\n proxyPassword: string;\r\n filterIpLocations?: string[];\r\n retriesWhenBlocked?: number;\r\n domainName?: string;\r\n proxyPort?: number;\r\n }) {\r\n super({ httpUrl: 'placeholder' });\r\n\r\n this.proxyUsername = options.proxyUsername;\r\n this.proxyPassword = options.proxyPassword;\r\n this.domainName = options.domainName || WebshareProxyConfig.DEFAULT_DOMAIN_NAME;\r\n this.proxyPort = options.proxyPort || WebshareProxyConfig.DEFAULT_PORT;\r\n this.filterIpLocations = options.filterIpLocations || [];\r\n this._retriesWhenBlocked = options.retriesWhenBlocked ?? 10;\r\n }\r\n\r\n /**\r\n * Gets the full proxy URL with location filtering and rotation settings.\r\n * @returns {string} The complete proxy URL\r\n */\r\n get url(): string {\r\n const locationCodes = this.filterIpLocations\r\n .map(code => `-${code.toUpperCase()}`)\r\n .join('');\r\n\r\n let username = this.proxyUsername;\r\n const suffix = '-rotate';\r\n\r\n if (username.endsWith(suffix)) {\r\n username = username.slice(0, -suffix.length);\r\n }\r\n\r\n return (\r\n `http://${username}${locationCodes}${suffix}:${this.proxyPassword}` +\r\n `@${this.domainName}:${this.proxyPort}/`\r\n );\r\n }\r\n\r\n get httpUrl(): string {\r\n return this.url;\r\n }\r\n\r\n get httpsUrl(): string {\r\n return this.url;\r\n }\r\n\r\n toRequestsDict(): RequestsProxyConfigDict {\r\n return {\r\n http: this.url,\r\n https: this.url\r\n };\r\n }\r\n\r\n get preventKeepingConnectionsAlive(): boolean {\r\n return true;\r\n }\r\n\r\n get retriesWhenBlocked(): number {\r\n return this._retriesWhenBlocked;\r\n }\r\n}\r\n","/**\r\n * @fileoverview All formatter classes for transcript formatting\r\n */\r\n\r\nimport type { FetchedTranscript } from '../models/fetched-transcript';\r\nimport type { FetchedTranscriptSnippet } from '../types';\r\n\r\n/**\r\n * Base abstract class for all transcript formatters.\r\n */\r\nexport abstract class Formatter {\r\n abstract formatTranscript(transcript: FetchedTranscript, options?: any): string;\r\n abstract formatTranscripts(transcripts: FetchedTranscript[], options?: any): string;\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to pretty-printed JSON format.\r\n */\r\nexport class PrettyPrintFormatter extends Formatter {\r\n formatTranscript(transcript: FetchedTranscript): string {\r\n return JSON.stringify(transcript.toRawData(), null, 2);\r\n }\r\n\r\n formatTranscripts(transcripts: FetchedTranscript[]): string {\r\n return JSON.stringify(transcripts.map(t => t.toRawData()), null, 2);\r\n }\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to JSON format.\r\n */\r\nexport class JSONFormatter extends Formatter {\r\n formatTranscript(transcript: FetchedTranscript, options?: { indent?: number }): string {\r\n return JSON.stringify(transcript.toRawData(), null, options?.indent);\r\n }\r\n\r\n formatTranscripts(transcripts: FetchedTranscript[], options?: { indent?: number }): string {\r\n return JSON.stringify(transcripts.map(t => t.toRawData()), null, options?.indent);\r\n }\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to plain text format with no timestamps.\r\n */\r\nexport class TextFormatter extends Formatter {\r\n formatTranscript(transcript: FetchedTranscript): string {\r\n return transcript.snippets.map(snippet => snippet.text).join('\\n');\r\n }\r\n\r\n formatTranscripts(transcripts: FetchedTranscript[]): string {\r\n return transcripts.map(t => this.formatTranscript(t)).join('\\n\\n\\n');\r\n }\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to article format with character-to-timestamp mappings.\r\n * Returns full text as a string along with character position to time pairings.\r\n */\r\nexport class ArticleFormatter extends Formatter {\r\n formatTranscript(transcript: FetchedTranscript): string {\r\n // Build full text content\r\n const fullText = transcript.snippets.map(snippet => snippet.text).join(' ');\r\n\r\n // Build timestamp mappings - track which character position corresponds to which time\r\n const timestamps: Array<[number, number]> = [];\r\n let charPosition = 0;\r\n\r\n for (const snippet of transcript.snippets) {\r\n // Record the character position and start time for this snippet\r\n timestamps.push([charPosition, snippet.start]);\r\n charPosition += snippet.text.length + 1; // +1 for the space separator\r\n }\r\n\r\n // Calculate character-per-second speeds at intervals\r\n const speedsEveryCharPeriod: { [key: number]: number } = {};\r\n const valueCharPeriod = 100;\r\n\r\n for (const [char, time] of timestamps) {\r\n const speed = Math.floor(char / time) - 10;\r\n speedsEveryCharPeriod[Math.floor(char / valueCharPeriod)] = speed;\r\n }\r\n\r\n // Compress the speed data\r\n const speeds = Object.keys(speedsEveryCharPeriod).map(\r\n (timeKey) => speedsEveryCharPeriod[parseInt(timeKey)]\r\n );\r\n\r\n const compressed: number[] = [];\r\n const compressedCount: number[] = [];\r\n let currentNum = speeds[0];\r\n let count = 1;\r\n\r\n for (let i = 1; i < speeds.length; i++) {\r\n if (speeds[i] === currentNum) {\r\n count++;\r\n } else {\r\n compressed.push(currentNum);\r\n compressedCount.push(count);\r\n currentNum = speeds[i];\r\n count = 1;\r\n }\r\n }\r\n compressed.push(currentNum);\r\n compressedCount.push(count);\r\n\r\n // Convert counts to cumulative positions\r\n let total = 0;\r\n const cumulativeCounts = compressedCount.map((c) => {\r\n total += c;\r\n return total;\r\n });\r\n\r\n // Format output with speeds and timestamps\r\n const speedsData = compressed.join(',') + ' ' + cumulativeCounts.join(',');\r\n\r\n // Remove extra spaces from full text\r\n const cleanedText = fullText.replace(/\\s+/g, ' ');\r\n\r\n return JSON.stringify({\r\n text: cleanedText,\r\n timestamps: speedsData,\r\n wordCount: cleanedText.split(/\\s+/).length,\r\n charCount: cleanedText.length\r\n }, null, 2);\r\n }\r\n\r\n formatTranscripts(transcripts: FetchedTranscript[]): string {\r\n return transcripts.map(t => this.formatTranscript(t)).join('\\n\\n');\r\n }\r\n}\r\n\r\n/**\r\n * Base class for subtitle formatters (SRT, WebVTT).\r\n */\r\nabstract class SubtitleFormatterBase extends TextFormatter {\r\n protected abstract formatTimestamp(h: number, m: number, s: number, ms: number): string;\r\n protected abstract formatTranscriptHeader(lines: string[]): string;\r\n protected abstract formatSubtitleEntry(index: number, timeRange: string, snippet: FetchedTranscriptSnippet): string;\r\n\r\n protected secondsToTimestamp(timeInSeconds: number): string {\r\n const hours = Math.floor(timeInSeconds / 3600);\r\n const remainder = timeInSeconds % 3600;\r\n const minutes = Math.floor(remainder / 60);\r\n const seconds = Math.floor(remainder % 60);\r\n const milliseconds = Math.round((timeInSeconds - Math.floor(timeInSeconds)) * 1000);\r\n\r\n return this.formatTimestamp(hours, minutes, seconds, milliseconds);\r\n }\r\n\r\n formatTranscript(transcript: FetchedTranscript): string {\r\n const formattedLines: string[] = [];\r\n\r\n for (let i = 0; i < transcript.snippets.length; i++) {\r\n const snippet = transcript.snippets[i];\r\n const snippetEndTime = snippet.start + snippet.duration;\r\n\r\n const actualEndTime =\r\n i < transcript.snippets.length - 1 && transcript.snippets[i + 1].start < snippetEndTime\r\n ? transcript.snippets[i + 1].start\r\n : snippetEndTime;\r\n\r\n const timeRangeText = `${this.secondsToTimestamp(snippet.start)} --> ${this.secondsToTimestamp(actualEndTime)}`;\r\n\r\n formattedLines.push(this.formatSubtitleEntry(i, timeRangeText, snippet));\r\n }\r\n\r\n return this.formatTranscriptHeader(formattedLines);\r\n }\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to SRT (SubRip) format.\r\n */\r\nexport class SRTFormatter extends SubtitleFormatterBase {\r\n protected formatTimestamp(h: number, m: number, s: number, ms: number): string {\r\n const pad = (n: number, w: number) => n.toString().padStart(w, '0');\r\n return `${pad(h, 2)}:${pad(m, 2)}:${pad(s, 2)},${pad(ms, 3)}`;\r\n }\r\n\r\n protected formatTranscriptHeader(lines: string[]): string {\r\n return lines.join('\\n\\n') + '\\n';\r\n }\r\n\r\n protected formatSubtitleEntry(index: number, timeRange: string, snippet: FetchedTranscriptSnippet): string {\r\n return `${index + 1}\\n${timeRange}\\n${snippet.text}`;\r\n }\r\n}\r\n\r\n/**\r\n * Formatter that converts transcripts to WebVTT format.\r\n */\r\nexport class WebVTTFormatter extends SubtitleFormatterBase {\r\n protected formatTimestamp(h: number, m: number, s: number, ms: number): string {\r\n const pad = (n: number, w: number) => n.toString().padStart(w, '0');\r\n return `${pad(h, 2)}:${pad(m, 2)}:${pad(s, 2)}.${pad(ms, 3)}`;\r\n }\r\n\r\n protected formatTranscriptHeader(lines: string[]): string {\r\n return 'WEBVTT\\n\\n' + lines.join('\\n\\n') + '\\n';\r\n }\r\n\r\n protected formatSubtitleEntry(index: number, timeRange: string, snippet: FetchedTranscriptSnippet): string {\r\n return `${timeRange}\\n${snippet.text}`;\r\n }\r\n}\r\n\r\n/**\r\n * Raised when an unknown formatter type is requested.\r\n */\r\nexport class UnknownFormatterType extends Error {\r\n constructor(formatterType: string) {\r\n super(`Unknown formatter type: ${formatterType}. Available types: json, text, srt, webvtt, pretty, article`);\r\n this.name = 'UnknownFormatterType';\r\n Object.setPrototypeOf(this, UnknownFormatterType.prototype);\r\n }\r\n}\r\n\r\n/**\r\n * Utility class for loading formatters by type string.\r\n */\r\nexport class FormatterLoader {\r\n load(formatterType?: string): Formatter {\r\n const type = formatterType?.toLowerCase() || 'pretty';\r\n\r\n switch (type) {\r\n case 'json':\r\n return new JSONFormatter();\r\n case 'text':\r\n return new TextFormatter();\r\n case 'article':\r\n return new ArticleFormatter();\r\n case 'srt':\r\n return new SRTFormatter();\r\n case 'webvtt':\r\n return new WebVTTFormatter();\r\n case 'pretty':\r\n return new PrettyPrintFormatter();\r\n default:\r\n throw new UnknownFormatterType(type);\r\n }\r\n }\r\n}\r\n","{\n \"name\": \"extract-youtube\",\n \"version\": \"1.0.414\",\n \"description\": \"Fast, no-browser serverless-optimized YouTube transcript extractor, with optional React UI: a floating YouTube player and a synced-transcript modal\",\n \"main\": \"dist/index.cjs\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.mjs\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./react\": {\n \"types\": \"./dist/react/index.d.ts\",\n \"import\": \"./dist/react/index.mjs\",\n \"require\": \"./dist/react/index.cjs\"\n }\n },\n \"//bin\": \"Spelled out as an object with a relative path. npm normalizes the string form itself and prints a notice for it on every publish.\",\n \"bin\": {\n \"extract-youtube\": \"dist/cli.js\"\n },\n \"//files\": \"Publish only what consumers resolve. Without this the tarball also carries test/, jest.config.js, tsconfig*.json and vite.config.ts. Matches extract-webpage and extract-pdf.\",\n \"files\": [\n \"dist\",\n \"src\"\n ],\n \"scripts\": {\n \"clean\": \"node -e \\\"require('fs').rmSync('dist',{recursive:true,force:true})\\\"\",\n \"build\": \"npm run clean && npm run build:lib && npm run build:cli && npm run build:react && npm run build:types\",\n \"build:types\": \"tsc --emitDeclarationOnly --declaration --declarationMap\",\n \"build:lib\": \"vite build\",\n \"build:cli\": \"BUILD_CLI=true vite build\",\n \"build:react\": \"BUILD_REACT=true vite build\",\n \"build:bundle\": \"npm run build:lib && npm run build:cli && npm run build:react\",\n \"build:legacy\": \"tsc\",\n \"ship\": \"npm run build && npx standard-version --release-as patch; npm publish\",\n \"test\": \"jest\",\n \"test:coverage\": \"jest --coverage\",\n \"test:speeds\": \"bun src/cli.ts dQw4w9WgXcQ -f speeds\",\n \"lint\": \"eslint src --ext .ts\",\n \"demo\": \"cd demo && npm install && npm run dev\"\n },\n \"keywords\": [\n \"youtube\",\n \"transcript\",\n \"subtitles\",\n \"captions\",\n \"api\",\n \"serverless\",\n \"lambda\",\n \"vercel\",\n \"cloudflare\",\n \"edge\",\n \"typescript\",\n \"youtube-transcript\",\n \"youtube-transcript-api\",\n \"srt\",\n \"webvtt\",\n \"video\",\n \"parsing\",\n \"extraction\",\n \"optimized\",\n \"react\",\n \"floating-player\",\n \"picture-in-picture\",\n \"video-player\",\n \"youtube-player\",\n \"playlist\"\n ],\n \"author\": \"\",\n \"license\": \"rights.institute/PROSPER\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/OpenSourceAGI/qwksearch-research-agent.git\",\n \"directory\": \"packages/extract-youtube\"\n },\n \"dependencies\": {\n \"fast-xml-parser\": \"^5.11.1\",\n \"html-entities\": \"^2.6.0\",\n \"https-proxy-agent\": \"^9.1.0\",\n \"grab-url\": \"^1.6.22\",\n \"youtube-transcript-api\": \"^3.0.6\"\n },\n \"peerDependencies\": {\n \"react\": \">=18\",\n \"react-dom\": \">=18\",\n \"lucide-react\": \"^0.300.0 || ^1.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"react\": {\n \"optional\": true\n },\n \"react-dom\": {\n \"optional\": true\n },\n \"lucide-react\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@types/jest\": \"^30.0.0\",\n \"@types/node\": \"^26.5.0\",\n \"@types/react\": \"^19.2.18\",\n \"@types/react-dom\": \"^19.2.7\",\n \"jest\": \"^30.5.1\",\n \"lucide-react\": \"^1.43.0\",\n \"react\": \"^19.2.8\",\n \"react-dom\": \"^19.2.8\",\n \"terser\": \"^5.51.2\",\n \"ts-jest\": \"^29.4.12\",\n \"typescript\": \"npm:@typescript/typescript6@^6.0.2\",\n \"vite\": \"^8.2.2\"\n },\n \"engines\": {\n \"node\": \">=14.0.0\"\n }\n}","#!/usr/bin/env node\r\n/**\r\n * @fileoverview CLI for extracting YouTube transcripts\r\n */\r\n\r\nimport { YouTubeTranscriptApi } from './youtube-transcript-api';\r\nimport { encodeTranscriptSpeeds } from './utils/transcript-utils';\r\nimport { GenericProxyConfig, WebshareProxyConfig } from './proxies';\r\nimport {\r\n JSONFormatter,\r\n TextFormatter,\r\n SRTFormatter,\r\n WebVTTFormatter,\r\n PrettyPrintFormatter\r\n} from './formatters';\r\n\r\ninterface CliOptions {\r\n videoId: string;\r\n languages?: string[];\r\n format?: 'json' | 'text' | 'srt' | 'webvtt' | 'pretty' | 'speeds';\r\n preserveFormatting?: boolean;\r\n proxy?: string;\r\n webshareUser?: string;\r\n websharePass?: string;\r\n help?: boolean;\r\n version?: boolean;\r\n}\r\n\r\nfunction parseArgs(): CliOptions {\r\n const args = process.argv.slice(2);\r\n const options: CliOptions = { videoId: '' };\r\n\r\n for (let i = 0; i < args.length; i++) {\r\n const arg = args[i];\r\n\r\n switch (arg) {\r\n case '-h':\r\n case '--help':\r\n options.help = true;\r\n break;\r\n case '-v':\r\n case '--version':\r\n options.version = true;\r\n break;\r\n case '-l':\r\n case '--languages':\r\n options.languages = args[++i]?.split(',').map(l => l.trim());\r\n break;\r\n case '-f':\r\n case '--format':\r\n options.format = args[++i] as CliOptions['format'];\r\n break;\r\n case '-p':\r\n case '--preserve-formatting':\r\n options.preserveFormatting = true;\r\n break;\r\n case '--proxy':\r\n options.proxy = args[++i];\r\n break;\r\n case '--webshare-user':\r\n options.webshareUser = args[++i];\r\n break;\r\n case '--webshare-pass':\r\n options.websharePass = args[++i];\r\n break;\r\n default:\r\n if (!arg.startsWith('-') && !options.videoId) {\r\n options.videoId = arg;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n return options;\r\n}\r\n\r\nfunction showHelp() {\r\n console.log(`\r\nextract-youtube - Extract YouTube video transcripts\r\n\r\nUSAGE:\r\n extract-youtube <video-id> [options]\r\n\r\nOPTIONS:\r\n -h, --help Show this help message\r\n -v, --version Show version number\r\n -l, --languages <codes> Comma-separated language codes (e.g., en,de,fr)\r\n -f, --format <type> Output format: json, text, srt, webvtt, pretty, speeds (default: json)\r\n -p, --preserve-formatting Preserve text formatting (line breaks, etc.)\r\n --proxy <url> HTTP/HTTPS proxy URL\r\n --webshare-user <username> Webshare proxy username\r\n --webshare-pass <password> Webshare proxy password\r\n\r\nEXAMPLES:\r\n # Extract transcript in JSON format\r\n extract-youtube jNQXAC9IVRw\r\n\r\n # Extract transcript in SRT format\r\n extract-youtube jNQXAC9IVRw -f srt\r\n\r\n # Extract transcript with specific languages\r\n extract-youtube jNQXAC9IVRw -l en,de\r\n\r\n # Extract transcript with proxy\r\n extract-youtube jNQXAC9IVRw --proxy http://proxy.example.com:8080\r\n\r\n # Extract transcript with Webshare proxy\r\n extract-youtube jNQXAC9IVRw --webshare-user myuser --webshare-pass mypass\r\n\r\n # Extract transcript as plain text with preserved formatting\r\n extract-youtube jNQXAC9IVRw -f text -p\r\n\r\n # Extract speech speed encoding with joined text and timestamps\r\n extract-youtube jNQXAC9IVRw -f speeds\r\n`);\r\n}\r\n\r\nfunction showVersion() {\r\n const pkg = require('../package.json');\r\n console.log(`extract-youtube v${pkg.version}`);\r\n}\r\n\r\nasync function main() {\r\n const options = parseArgs();\r\n\r\n if (options.help) {\r\n showHelp();\r\n process.exit(0);\r\n }\r\n\r\n if (options.version) {\r\n showVersion();\r\n process.exit(0);\r\n }\r\n\r\n if (!options.videoId) {\r\n console.error('Error: Video ID is required\\n');\r\n showHelp();\r\n process.exit(1);\r\n }\r\n\r\n try {\r\n // Setup proxy configuration\r\n let proxyConfig;\r\n if (options.webshareUser && options.websharePass) {\r\n proxyConfig = new WebshareProxyConfig({\r\n proxyUsername: options.webshareUser,\r\n proxyPassword: options.websharePass\r\n });\r\n } else if (options.proxy) {\r\n proxyConfig = new GenericProxyConfig({\r\n httpUrl: options.proxy\r\n });\r\n }\r\n\r\n // Create API instance\r\n const api = new YouTubeTranscriptApi({ proxyConfig });\r\n\r\n // Fetch transcript\r\n const transcript = await api.fetchTranscript(options.videoId, {\r\n languages: options.languages,\r\n preserveFormatting: options.preserveFormatting\r\n });\r\n\r\n // Format output\r\n const format = options.format || 'json';\r\n let output: string;\r\n\r\n switch (format) {\r\n case 'json':\r\n output = new JSONFormatter().formatTranscript(transcript);\r\n break;\r\n case 'text':\r\n output = new TextFormatter().formatTranscript(transcript);\r\n break;\r\n case 'srt':\r\n output = new SRTFormatter().formatTranscript(transcript);\r\n break;\r\n case 'webvtt':\r\n output = new WebVTTFormatter().formatTranscript(transcript);\r\n break;\r\n case 'pretty':\r\n output = new PrettyPrintFormatter().formatTranscript(transcript);\r\n break;\r\n case 'speeds': {\r\n const { html, word_count, speeds } = encodeTranscriptSpeeds(transcript);\r\n output = JSON.stringify({ html, word_count, speeds });\r\n break;\r\n }\r\n default:\r\n throw new Error(`Unknown format: ${format}`);\r\n }\r\n\r\n console.log(output);\r\n process.exit(0);\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n console.error(`Error: ${error.message}`);\r\n } else {\r\n console.error(`Error: ${String(error)}`);\r\n }\r\n process.exit(1);\r\n }\r\n}\r\n\r\nmain();\r\n"],"x_google_ignoreList":[9,10,11],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "extract-youtube",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.415",
|
|
4
4
|
"description": "Fast, no-browser serverless-optimized YouTube transcript extractor, with optional React UI: a floating YouTube player and a synced-transcript modal",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|