youtube-transcript-nodejs 0.1.0
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/LICENSE +21 -0
- package/README.md +337 -0
- package/dist/cjs/api/InnerTubeClient.js +236 -0
- package/dist/cjs/api/InnerTubeClient.js.map +1 -0
- package/dist/cjs/api/YouTubeTranscriptApi.js +160 -0
- package/dist/cjs/api/YouTubeTranscriptApi.js.map +1 -0
- package/dist/cjs/api/fetchStrategies.js +51 -0
- package/dist/cjs/api/fetchStrategies.js.map +1 -0
- package/dist/cjs/config/constants.js +34 -0
- package/dist/cjs/config/constants.js.map +1 -0
- package/dist/cjs/config/innerTubeContext.js +82 -0
- package/dist/cjs/config/innerTubeContext.js.map +1 -0
- package/dist/cjs/errors/BotDetected.js +20 -0
- package/dist/cjs/errors/BotDetected.js.map +1 -0
- package/dist/cjs/errors/FailedToCreateConsentCookie.js +17 -0
- package/dist/cjs/errors/FailedToCreateConsentCookie.js.map +1 -0
- package/dist/cjs/errors/InvalidVideoId.js +16 -0
- package/dist/cjs/errors/InvalidVideoId.js.map +1 -0
- package/dist/cjs/errors/IpBlocked.js +17 -0
- package/dist/cjs/errors/IpBlocked.js.map +1 -0
- package/dist/cjs/errors/NoTranscriptFound.js +23 -0
- package/dist/cjs/errors/NoTranscriptFound.js.map +1 -0
- package/dist/cjs/errors/NotTranslatable.js +15 -0
- package/dist/cjs/errors/NotTranslatable.js.map +1 -0
- package/dist/cjs/errors/PoTokenRequired.js +18 -0
- package/dist/cjs/errors/PoTokenRequired.js.map +1 -0
- package/dist/cjs/errors/TooManyRequests.js +19 -0
- package/dist/cjs/errors/TooManyRequests.js.map +1 -0
- package/dist/cjs/errors/TranscriptsDisabled.js +15 -0
- package/dist/cjs/errors/TranscriptsDisabled.js.map +1 -0
- package/dist/cjs/errors/TranslationLanguageNotAvailable.js +16 -0
- package/dist/cjs/errors/TranslationLanguageNotAvailable.js.map +1 -0
- package/dist/cjs/errors/VideoUnavailable.js +15 -0
- package/dist/cjs/errors/VideoUnavailable.js.map +1 -0
- package/dist/cjs/errors/VideoUnplayable.js +22 -0
- package/dist/cjs/errors/VideoUnplayable.js.map +1 -0
- package/dist/cjs/errors/YouTubeDataUnparsable.js +15 -0
- package/dist/cjs/errors/YouTubeDataUnparsable.js.map +1 -0
- package/dist/cjs/errors/YouTubeRequestFailed.js +18 -0
- package/dist/cjs/errors/YouTubeRequestFailed.js.map +1 -0
- package/dist/cjs/errors/YouTubeTranscriptError.js +19 -0
- package/dist/cjs/errors/YouTubeTranscriptError.js.map +1 -0
- package/dist/cjs/errors/index.js +34 -0
- package/dist/cjs/errors/index.js.map +1 -0
- package/dist/cjs/formatters/Formatter.js +3 -0
- package/dist/cjs/formatters/Formatter.js.map +1 -0
- package/dist/cjs/formatters/JSONFormatter.js +24 -0
- package/dist/cjs/formatters/JSONFormatter.js.map +1 -0
- package/dist/cjs/formatters/PrettyPrintFormatter.js +26 -0
- package/dist/cjs/formatters/PrettyPrintFormatter.js.map +1 -0
- package/dist/cjs/formatters/SRTFormatter.js +39 -0
- package/dist/cjs/formatters/SRTFormatter.js.map +1 -0
- package/dist/cjs/formatters/TextFormatter.js +20 -0
- package/dist/cjs/formatters/TextFormatter.js.map +1 -0
- package/dist/cjs/formatters/WebVTTFormatter.js +39 -0
- package/dist/cjs/formatters/WebVTTFormatter.js.map +1 -0
- package/dist/cjs/formatters/base.js +61 -0
- package/dist/cjs/formatters/base.js.map +1 -0
- package/dist/cjs/formatters/index.js +19 -0
- package/dist/cjs/formatters/index.js.map +1 -0
- package/dist/cjs/http/cookieJar.js +91 -0
- package/dist/cjs/http/cookieJar.js.map +1 -0
- package/dist/cjs/http/httpClient.js +228 -0
- package/dist/cjs/http/httpClient.js.map +1 -0
- package/dist/cjs/index.js +50 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/models/FetchedTranscript.js +80 -0
- package/dist/cjs/models/FetchedTranscript.js.map +1 -0
- package/dist/cjs/models/FetchedTranscriptSnippet.js +29 -0
- package/dist/cjs/models/FetchedTranscriptSnippet.js.map +1 -0
- package/dist/cjs/models/FormattedTranscript.js +3 -0
- package/dist/cjs/models/FormattedTranscript.js.map +1 -0
- package/dist/cjs/models/Transcript.js +75 -0
- package/dist/cjs/models/Transcript.js.map +1 -0
- package/dist/cjs/models/TranscriptList.js +84 -0
- package/dist/cjs/models/TranscriptList.js.map +1 -0
- package/dist/cjs/models/TranscriptMetadata.js +3 -0
- package/dist/cjs/models/TranscriptMetadata.js.map +1 -0
- package/dist/cjs/models/TranslationLanguage.js +3 -0
- package/dist/cjs/models/TranslationLanguage.js.map +1 -0
- package/dist/cjs/models/index.js +13 -0
- package/dist/cjs/models/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/parsers/captionTrackParser.js +96 -0
- package/dist/cjs/parsers/captionTrackParser.js.map +1 -0
- package/dist/cjs/parsers/videoIdParser.js +65 -0
- package/dist/cjs/parsers/videoIdParser.js.map +1 -0
- package/dist/cjs/parsers/watchHtmlParser.js +78 -0
- package/dist/cjs/parsers/watchHtmlParser.js.map +1 -0
- package/dist/cjs/parsers/xmlTranscriptParser.js +84 -0
- package/dist/cjs/parsers/xmlTranscriptParser.js.map +1 -0
- package/dist/cjs/potoken/AutoPoTokenProvider.js +203 -0
- package/dist/cjs/potoken/AutoPoTokenProvider.js.map +1 -0
- package/dist/cjs/potoken/HttpPoTokenProvider.js +105 -0
- package/dist/cjs/potoken/HttpPoTokenProvider.js.map +1 -0
- package/dist/cjs/potoken/NoopPoTokenProvider.js +18 -0
- package/dist/cjs/potoken/NoopPoTokenProvider.js.map +1 -0
- package/dist/cjs/potoken/baseScriptCache.js +41 -0
- package/dist/cjs/potoken/baseScriptCache.js.map +1 -0
- package/dist/cjs/potoken/index.js +14 -0
- package/dist/cjs/potoken/index.js.map +1 -0
- package/dist/cjs/potoken/types.js +10 -0
- package/dist/cjs/potoken/types.js.map +1 -0
- package/dist/cjs/util/htmlSanitizer.js +77 -0
- package/dist/cjs/util/htmlSanitizer.js.map +1 -0
- package/dist/cjs/util/proxyUrl.js +42 -0
- package/dist/cjs/util/proxyUrl.js.map +1 -0
- package/dist/cjs/util/retry.js +65 -0
- package/dist/cjs/util/retry.js.map +1 -0
- package/dist/esm/api/InnerTubeClient.d.ts +61 -0
- package/dist/esm/api/InnerTubeClient.d.ts.map +1 -0
- package/dist/esm/api/InnerTubeClient.js +198 -0
- package/dist/esm/api/InnerTubeClient.js.map +1 -0
- package/dist/esm/api/YouTubeTranscriptApi.d.ts +88 -0
- package/dist/esm/api/YouTubeTranscriptApi.d.ts.map +1 -0
- package/dist/esm/api/YouTubeTranscriptApi.js +157 -0
- package/dist/esm/api/YouTubeTranscriptApi.js.map +1 -0
- package/dist/esm/api/fetchStrategies.d.ts +20 -0
- package/dist/esm/api/fetchStrategies.d.ts.map +1 -0
- package/dist/esm/api/fetchStrategies.js +48 -0
- package/dist/esm/api/fetchStrategies.js.map +1 -0
- package/dist/esm/config/constants.d.ts +30 -0
- package/dist/esm/config/constants.d.ts.map +1 -0
- package/dist/esm/config/constants.js +31 -0
- package/dist/esm/config/constants.js.map +1 -0
- package/dist/esm/config/innerTubeContext.d.ts +47 -0
- package/dist/esm/config/innerTubeContext.d.ts.map +1 -0
- package/dist/esm/config/innerTubeContext.js +77 -0
- package/dist/esm/config/innerTubeContext.js.map +1 -0
- package/dist/esm/errors/BotDetected.d.ts +13 -0
- package/dist/esm/errors/BotDetected.d.ts.map +1 -0
- package/dist/esm/errors/BotDetected.js +16 -0
- package/dist/esm/errors/BotDetected.js.map +1 -0
- package/dist/esm/errors/FailedToCreateConsentCookie.d.ts +10 -0
- package/dist/esm/errors/FailedToCreateConsentCookie.d.ts.map +1 -0
- package/dist/esm/errors/FailedToCreateConsentCookie.js +13 -0
- package/dist/esm/errors/FailedToCreateConsentCookie.js.map +1 -0
- package/dist/esm/errors/InvalidVideoId.d.ts +9 -0
- package/dist/esm/errors/InvalidVideoId.d.ts.map +1 -0
- package/dist/esm/errors/InvalidVideoId.js +12 -0
- package/dist/esm/errors/InvalidVideoId.js.map +1 -0
- package/dist/esm/errors/IpBlocked.d.ts +10 -0
- package/dist/esm/errors/IpBlocked.d.ts.map +1 -0
- package/dist/esm/errors/IpBlocked.js +13 -0
- package/dist/esm/errors/IpBlocked.js.map +1 -0
- package/dist/esm/errors/NoTranscriptFound.d.ts +19 -0
- package/dist/esm/errors/NoTranscriptFound.d.ts.map +1 -0
- package/dist/esm/errors/NoTranscriptFound.js +19 -0
- package/dist/esm/errors/NoTranscriptFound.js.map +1 -0
- package/dist/esm/errors/NotTranslatable.d.ts +9 -0
- package/dist/esm/errors/NotTranslatable.d.ts.map +1 -0
- package/dist/esm/errors/NotTranslatable.js +11 -0
- package/dist/esm/errors/NotTranslatable.js.map +1 -0
- package/dist/esm/errors/PoTokenRequired.d.ts +10 -0
- package/dist/esm/errors/PoTokenRequired.d.ts.map +1 -0
- package/dist/esm/errors/PoTokenRequired.js +14 -0
- package/dist/esm/errors/PoTokenRequired.js.map +1 -0
- package/dist/esm/errors/TooManyRequests.d.ts +12 -0
- package/dist/esm/errors/TooManyRequests.d.ts.map +1 -0
- package/dist/esm/errors/TooManyRequests.js +15 -0
- package/dist/esm/errors/TooManyRequests.js.map +1 -0
- package/dist/esm/errors/TranscriptsDisabled.d.ts +9 -0
- package/dist/esm/errors/TranscriptsDisabled.d.ts.map +1 -0
- package/dist/esm/errors/TranscriptsDisabled.js +11 -0
- package/dist/esm/errors/TranscriptsDisabled.js.map +1 -0
- package/dist/esm/errors/TranslationLanguageNotAvailable.d.ts +9 -0
- package/dist/esm/errors/TranslationLanguageNotAvailable.d.ts.map +1 -0
- package/dist/esm/errors/TranslationLanguageNotAvailable.js +12 -0
- package/dist/esm/errors/TranslationLanguageNotAvailable.js.map +1 -0
- package/dist/esm/errors/VideoUnavailable.d.ts +9 -0
- package/dist/esm/errors/VideoUnavailable.d.ts.map +1 -0
- package/dist/esm/errors/VideoUnavailable.js +11 -0
- package/dist/esm/errors/VideoUnavailable.js.map +1 -0
- package/dist/esm/errors/VideoUnplayable.d.ts +12 -0
- package/dist/esm/errors/VideoUnplayable.d.ts.map +1 -0
- package/dist/esm/errors/VideoUnplayable.js +18 -0
- package/dist/esm/errors/VideoUnplayable.js.map +1 -0
- package/dist/esm/errors/YouTubeDataUnparsable.d.ts +9 -0
- package/dist/esm/errors/YouTubeDataUnparsable.d.ts.map +1 -0
- package/dist/esm/errors/YouTubeDataUnparsable.js +11 -0
- package/dist/esm/errors/YouTubeDataUnparsable.js.map +1 -0
- package/dist/esm/errors/YouTubeRequestFailed.d.ts +10 -0
- package/dist/esm/errors/YouTubeRequestFailed.d.ts.map +1 -0
- package/dist/esm/errors/YouTubeRequestFailed.js +14 -0
- package/dist/esm/errors/YouTubeRequestFailed.js.map +1 -0
- package/dist/esm/errors/YouTubeTranscriptError.d.ts +10 -0
- package/dist/esm/errors/YouTubeTranscriptError.d.ts.map +1 -0
- package/dist/esm/errors/YouTubeTranscriptError.js +15 -0
- package/dist/esm/errors/YouTubeTranscriptError.js.map +1 -0
- package/dist/esm/errors/index.d.ts +17 -0
- package/dist/esm/errors/index.d.ts.map +1 -0
- package/dist/esm/errors/index.js +16 -0
- package/dist/esm/errors/index.js.map +1 -0
- package/dist/esm/formatters/Formatter.d.ts +33 -0
- package/dist/esm/formatters/Formatter.d.ts.map +1 -0
- package/dist/esm/formatters/Formatter.js +2 -0
- package/dist/esm/formatters/Formatter.js.map +1 -0
- package/dist/esm/formatters/JSONFormatter.d.ts +10 -0
- package/dist/esm/formatters/JSONFormatter.d.ts.map +1 -0
- package/dist/esm/formatters/JSONFormatter.js +20 -0
- package/dist/esm/formatters/JSONFormatter.js.map +1 -0
- package/dist/esm/formatters/PrettyPrintFormatter.d.ts +15 -0
- package/dist/esm/formatters/PrettyPrintFormatter.d.ts.map +1 -0
- package/dist/esm/formatters/PrettyPrintFormatter.js +22 -0
- package/dist/esm/formatters/PrettyPrintFormatter.js.map +1 -0
- package/dist/esm/formatters/SRTFormatter.d.ts +22 -0
- package/dist/esm/formatters/SRTFormatter.d.ts.map +1 -0
- package/dist/esm/formatters/SRTFormatter.js +35 -0
- package/dist/esm/formatters/SRTFormatter.js.map +1 -0
- package/dist/esm/formatters/TextFormatter.d.ts +10 -0
- package/dist/esm/formatters/TextFormatter.d.ts.map +1 -0
- package/dist/esm/formatters/TextFormatter.js +16 -0
- package/dist/esm/formatters/TextFormatter.js.map +1 -0
- package/dist/esm/formatters/WebVTTFormatter.d.ts +22 -0
- package/dist/esm/formatters/WebVTTFormatter.d.ts.map +1 -0
- package/dist/esm/formatters/WebVTTFormatter.js +35 -0
- package/dist/esm/formatters/WebVTTFormatter.js.map +1 -0
- package/dist/esm/formatters/base.d.ts +25 -0
- package/dist/esm/formatters/base.d.ts.map +1 -0
- package/dist/esm/formatters/base.js +55 -0
- package/dist/esm/formatters/base.js.map +1 -0
- package/dist/esm/formatters/index.d.ts +8 -0
- package/dist/esm/formatters/index.d.ts.map +1 -0
- package/dist/esm/formatters/index.js +7 -0
- package/dist/esm/formatters/index.js.map +1 -0
- package/dist/esm/http/cookieJar.d.ts +39 -0
- package/dist/esm/http/cookieJar.d.ts.map +1 -0
- package/dist/esm/http/cookieJar.js +87 -0
- package/dist/esm/http/cookieJar.js.map +1 -0
- package/dist/esm/http/httpClient.d.ts +88 -0
- package/dist/esm/http/httpClient.d.ts.map +1 -0
- package/dist/esm/http/httpClient.js +191 -0
- package/dist/esm/http/httpClient.js.map +1 -0
- package/dist/esm/index.d.ts +19 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +14 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/models/FetchedTranscript.d.ts +49 -0
- package/dist/esm/models/FetchedTranscript.d.ts.map +1 -0
- package/dist/esm/models/FetchedTranscript.js +76 -0
- package/dist/esm/models/FetchedTranscript.js.map +1 -0
- package/dist/esm/models/FetchedTranscriptSnippet.d.ts +15 -0
- package/dist/esm/models/FetchedTranscriptSnippet.d.ts.map +1 -0
- package/dist/esm/models/FetchedTranscriptSnippet.js +25 -0
- package/dist/esm/models/FetchedTranscriptSnippet.js.map +1 -0
- package/dist/esm/models/FormattedTranscript.d.ts +9 -0
- package/dist/esm/models/FormattedTranscript.d.ts.map +1 -0
- package/dist/esm/models/FormattedTranscript.js +2 -0
- package/dist/esm/models/FormattedTranscript.js.map +1 -0
- package/dist/esm/models/Transcript.d.ts +36 -0
- package/dist/esm/models/Transcript.d.ts.map +1 -0
- package/dist/esm/models/Transcript.js +71 -0
- package/dist/esm/models/Transcript.js.map +1 -0
- package/dist/esm/models/TranscriptList.d.ts +48 -0
- package/dist/esm/models/TranscriptList.d.ts.map +1 -0
- package/dist/esm/models/TranscriptList.js +79 -0
- package/dist/esm/models/TranscriptList.js.map +1 -0
- package/dist/esm/models/TranscriptMetadata.d.ts +10 -0
- package/dist/esm/models/TranscriptMetadata.d.ts.map +1 -0
- package/dist/esm/models/TranscriptMetadata.js +2 -0
- package/dist/esm/models/TranscriptMetadata.js.map +1 -0
- package/dist/esm/models/TranslationLanguage.d.ts +8 -0
- package/dist/esm/models/TranslationLanguage.d.ts.map +1 -0
- package/dist/esm/models/TranslationLanguage.js +2 -0
- package/dist/esm/models/TranslationLanguage.js.map +1 -0
- package/dist/esm/models/index.d.ts +8 -0
- package/dist/esm/models/index.d.ts.map +1 -0
- package/dist/esm/models/index.js +5 -0
- package/dist/esm/models/index.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/parsers/captionTrackParser.d.ts +29 -0
- package/dist/esm/parsers/captionTrackParser.d.ts.map +1 -0
- package/dist/esm/parsers/captionTrackParser.js +91 -0
- package/dist/esm/parsers/captionTrackParser.js.map +1 -0
- package/dist/esm/parsers/videoIdParser.d.ts +11 -0
- package/dist/esm/parsers/videoIdParser.d.ts.map +1 -0
- package/dist/esm/parsers/videoIdParser.js +61 -0
- package/dist/esm/parsers/videoIdParser.js.map +1 -0
- package/dist/esm/parsers/watchHtmlParser.d.ts +33 -0
- package/dist/esm/parsers/watchHtmlParser.d.ts.map +1 -0
- package/dist/esm/parsers/watchHtmlParser.js +70 -0
- package/dist/esm/parsers/watchHtmlParser.js.map +1 -0
- package/dist/esm/parsers/xmlTranscriptParser.d.ts +17 -0
- package/dist/esm/parsers/xmlTranscriptParser.d.ts.map +1 -0
- package/dist/esm/parsers/xmlTranscriptParser.js +81 -0
- package/dist/esm/parsers/xmlTranscriptParser.js.map +1 -0
- package/dist/esm/potoken/AutoPoTokenProvider.d.ts +28 -0
- package/dist/esm/potoken/AutoPoTokenProvider.d.ts.map +1 -0
- package/dist/esm/potoken/AutoPoTokenProvider.js +166 -0
- package/dist/esm/potoken/AutoPoTokenProvider.js.map +1 -0
- package/dist/esm/potoken/HttpPoTokenProvider.d.ts +41 -0
- package/dist/esm/potoken/HttpPoTokenProvider.d.ts.map +1 -0
- package/dist/esm/potoken/HttpPoTokenProvider.js +101 -0
- package/dist/esm/potoken/HttpPoTokenProvider.js.map +1 -0
- package/dist/esm/potoken/NoopPoTokenProvider.d.ts +12 -0
- package/dist/esm/potoken/NoopPoTokenProvider.d.ts.map +1 -0
- package/dist/esm/potoken/NoopPoTokenProvider.js +14 -0
- package/dist/esm/potoken/NoopPoTokenProvider.js.map +1 -0
- package/dist/esm/potoken/baseScriptCache.d.ts +28 -0
- package/dist/esm/potoken/baseScriptCache.d.ts.map +1 -0
- package/dist/esm/potoken/baseScriptCache.js +37 -0
- package/dist/esm/potoken/baseScriptCache.js.map +1 -0
- package/dist/esm/potoken/index.d.ts +10 -0
- package/dist/esm/potoken/index.d.ts.map +1 -0
- package/dist/esm/potoken/index.js +6 -0
- package/dist/esm/potoken/index.js.map +1 -0
- package/dist/esm/potoken/types.d.ts +40 -0
- package/dist/esm/potoken/types.d.ts.map +1 -0
- package/dist/esm/potoken/types.js +7 -0
- package/dist/esm/potoken/types.js.map +1 -0
- package/dist/esm/util/htmlSanitizer.d.ts +21 -0
- package/dist/esm/util/htmlSanitizer.d.ts.map +1 -0
- package/dist/esm/util/htmlSanitizer.js +69 -0
- package/dist/esm/util/htmlSanitizer.js.map +1 -0
- package/dist/esm/util/proxyUrl.d.ts +22 -0
- package/dist/esm/util/proxyUrl.d.ts.map +1 -0
- package/dist/esm/util/proxyUrl.js +39 -0
- package/dist/esm/util/proxyUrl.js.map +1 -0
- package/dist/esm/util/retry.d.ts +37 -0
- package/dist/esm/util/retry.d.ts.map +1 -0
- package/dist/esm/util/retry.js +60 -0
- package/dist/esm/util/retry.js.map +1 -0
- package/package.json +111 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { BotDetected } from '../errors/index.js';
|
|
2
|
+
import { isTokenFresh } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Self-contained PoToken provider.
|
|
5
|
+
*
|
|
6
|
+
* Uses `bgutils-js` (an optional dependency) to drive YouTube's BotGuard
|
|
7
|
+
* VM and mint PoTokens locally. No external service required.
|
|
8
|
+
*
|
|
9
|
+
* The visitorData is derived from the video id by default; pass a real
|
|
10
|
+
* one via `setVisitorData()` for stronger session-bound guarantees.
|
|
11
|
+
*
|
|
12
|
+
* Note: this provider requires the optional `bgutils-js` dependency. If
|
|
13
|
+
* it is not installed, generation throws `BotDetected`.
|
|
14
|
+
*/
|
|
15
|
+
const WAA_API_KEY = 'AIzaSyDyT5W0Jh49F30Pqqtyfdf7pDLFKLJoAnw';
|
|
16
|
+
const REQUEST_KEY = 'O43z0dpjhgX20SCx4KAo';
|
|
17
|
+
const CHALLENGE_URL = 'https://jnn-pa.googleapis.com/$rpc/google.internal.waa.v1.Waa/Create';
|
|
18
|
+
/**
|
|
19
|
+
* Lazy import of bgutils-js. Throws if the package is not installed.
|
|
20
|
+
*/
|
|
21
|
+
async function importBg() {
|
|
22
|
+
try {
|
|
23
|
+
const mod = (await import('bgutils-js'));
|
|
24
|
+
return mod.BG ?? mod;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class AutoPoTokenProvider {
|
|
31
|
+
fetchImpl;
|
|
32
|
+
ttlMs;
|
|
33
|
+
challengeTtlMs;
|
|
34
|
+
visitorData;
|
|
35
|
+
cache = null;
|
|
36
|
+
constructor(opts = {}) {
|
|
37
|
+
const f = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
38
|
+
if (!f) {
|
|
39
|
+
throw new Error('No fetch implementation available');
|
|
40
|
+
}
|
|
41
|
+
this.fetchImpl = f;
|
|
42
|
+
this.ttlMs = opts.ttlMs ?? 12 * 60 * 60 * 1000;
|
|
43
|
+
this.challengeTtlMs = opts.challengeTtlMs ?? 5 * 60 * 1000;
|
|
44
|
+
this.visitorData = opts.visitorData;
|
|
45
|
+
}
|
|
46
|
+
setVisitorData(visitorData) {
|
|
47
|
+
this.visitorData = visitorData;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Whether bgutils-js is installed and the provider is usable.
|
|
51
|
+
*/
|
|
52
|
+
isAvailable() {
|
|
53
|
+
// Synchronous check via require cache is unreliable; the real check
|
|
54
|
+
// happens lazily in generateForVideo().
|
|
55
|
+
try {
|
|
56
|
+
require.resolve('bgutils-js');
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async generateForVideo(videoId) {
|
|
64
|
+
if (this.cache?.lastVideoId === videoId &&
|
|
65
|
+
this.cache.lastTokenResult &&
|
|
66
|
+
isTokenFresh(this.cache.lastTokenResult, 60_000)) {
|
|
67
|
+
return this.cache.lastTokenResult;
|
|
68
|
+
}
|
|
69
|
+
const bg = await importBg();
|
|
70
|
+
if (!bg) {
|
|
71
|
+
throw new BotDetected(videoId);
|
|
72
|
+
}
|
|
73
|
+
const visitorData = this.visitorData ?? videoId;
|
|
74
|
+
try {
|
|
75
|
+
const challengeEntry = await this.getOrLoadChallenge(bg);
|
|
76
|
+
const botguard = await bg.BotGuardClient.create({
|
|
77
|
+
program: challengeEntry.challenge.program,
|
|
78
|
+
globalName: challengeEntry.challenge.globalName,
|
|
79
|
+
globalObj: challengeEntry.globalObj,
|
|
80
|
+
});
|
|
81
|
+
const result = await bg.PoToken.generate({
|
|
82
|
+
program: challengeEntry.challenge.program,
|
|
83
|
+
globalName: challengeEntry.challenge.globalName,
|
|
84
|
+
bgConfig: {
|
|
85
|
+
fetch: this.fetchImpl.bind(globalThis),
|
|
86
|
+
globalObj: challengeEntry.globalObj,
|
|
87
|
+
identifier: visitorData,
|
|
88
|
+
requestKey: REQUEST_KEY,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
const tokenResult = {
|
|
92
|
+
poToken: result.poToken,
|
|
93
|
+
visitorData,
|
|
94
|
+
expiresAt: new Date(Date.now() + this.ttlMs),
|
|
95
|
+
};
|
|
96
|
+
this.cache = {
|
|
97
|
+
...challengeEntry,
|
|
98
|
+
botguard,
|
|
99
|
+
lastVideoId: videoId,
|
|
100
|
+
lastTokenResult: tokenResult,
|
|
101
|
+
};
|
|
102
|
+
return tokenResult;
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
if (err instanceof BotDetected)
|
|
106
|
+
throw err;
|
|
107
|
+
throw new BotDetected(videoId);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async dispose() {
|
|
111
|
+
if (this.cache?.botguard?.shutdown) {
|
|
112
|
+
try {
|
|
113
|
+
await this.cache.botguard.shutdown();
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// ignore
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
this.cache = null;
|
|
120
|
+
}
|
|
121
|
+
async getOrLoadChallenge(bg) {
|
|
122
|
+
if (this.cache && Date.now() - this.cache.fetchedAt < this.challengeTtlMs) {
|
|
123
|
+
return this.cache;
|
|
124
|
+
}
|
|
125
|
+
const response = await this.fetchImpl(CHALLENGE_URL, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
headers: {
|
|
128
|
+
'Content-Type': 'application/json+protobuf',
|
|
129
|
+
'x-goog-api-key': WAA_API_KEY,
|
|
130
|
+
'x-user-agent': 'grpc-web-javascript/0.1',
|
|
131
|
+
},
|
|
132
|
+
body: JSON.stringify([REQUEST_KEY]),
|
|
133
|
+
});
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
throw new BotDetected('__challenge__');
|
|
136
|
+
}
|
|
137
|
+
const rawData = (await response.json());
|
|
138
|
+
const parsed = bg.Challenge.parseChallengeData
|
|
139
|
+
? bg.Challenge.parseChallengeData(rawData)
|
|
140
|
+
: rawData;
|
|
141
|
+
const challenge = parsed;
|
|
142
|
+
if (!challenge?.program || !challenge?.globalName) {
|
|
143
|
+
throw new BotDetected('__challenge__');
|
|
144
|
+
}
|
|
145
|
+
// Execute interpreter script to populate globalObj[globalName].
|
|
146
|
+
const globalObj = globalThis ?? {};
|
|
147
|
+
const script = challenge.interpreterJavascript.privateDoNotAccessOrElseSafeScriptWrappedValue;
|
|
148
|
+
if (typeof script === 'string' && script.length > 0 && !globalObj[challenge.globalName]) {
|
|
149
|
+
try {
|
|
150
|
+
new Function(script)();
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
throw new BotDetected('__challenge__');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const entry = {
|
|
157
|
+
challenge,
|
|
158
|
+
globalObj,
|
|
159
|
+
botguard: null,
|
|
160
|
+
fetchedAt: Date.now(),
|
|
161
|
+
};
|
|
162
|
+
this.cache = entry;
|
|
163
|
+
return entry;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=AutoPoTokenProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutoPoTokenProvider.js","sourceRoot":"","sources":["../../../src/potoken/AutoPoTokenProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type PoTokenProvider, type TokenResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for {@link HttpPoTokenProvider}.
|
|
4
|
+
*/
|
|
5
|
+
export interface HttpPoTokenProviderOptions {
|
|
6
|
+
/** Base URL of the pot provider (e.g. http://localhost:4416). */
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
/** Request timeout in ms. */
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
/** Custom fetch implementation. */
|
|
11
|
+
fetchImpl?: typeof fetch;
|
|
12
|
+
/** Token TTL — how long we treat a returned token as fresh. */
|
|
13
|
+
ttlMs?: number;
|
|
14
|
+
/** AbortSignal for cancellation. */
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Talks to a `bgutil-ytdlp-pot-provider`-compatible HTTP endpoint to fetch
|
|
19
|
+
* PoTokens. Useful for users who already run the provider as a sidecar.
|
|
20
|
+
*
|
|
21
|
+
* Protocol (compatible with bgutil-ytdlp-pot-provider):
|
|
22
|
+
*
|
|
23
|
+
* POST {baseUrl}/get_pot
|
|
24
|
+
* Content-Type: application/json
|
|
25
|
+
* Body: { video_id, visitor_data? }
|
|
26
|
+
* → 200 { po_token, visitor_data, expiration? }
|
|
27
|
+
*
|
|
28
|
+
* If the server returns no token, throws `BotDetected`.
|
|
29
|
+
*/
|
|
30
|
+
export declare class HttpPoTokenProvider implements PoTokenProvider {
|
|
31
|
+
private readonly baseUrl;
|
|
32
|
+
private readonly timeoutMs;
|
|
33
|
+
private readonly fetchImpl;
|
|
34
|
+
private readonly ttlMs;
|
|
35
|
+
private cache;
|
|
36
|
+
private readonly signal?;
|
|
37
|
+
constructor(opts: HttpPoTokenProviderOptions);
|
|
38
|
+
generateForVideo(videoId: string): Promise<TokenResult>;
|
|
39
|
+
dispose(): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=HttpPoTokenProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpPoTokenProvider.d.ts","sourceRoot":"","sources":["../../../src/potoken/HttpPoTokenProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAElF;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,KAAK,CAAyD;IACtE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAc;gBAE1B,IAAI,EAAE,0BAA0B;IAetC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAqDvD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { BotDetected } from '../errors/index.js';
|
|
2
|
+
import { isTokenFresh } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Talks to a `bgutil-ytdlp-pot-provider`-compatible HTTP endpoint to fetch
|
|
5
|
+
* PoTokens. Useful for users who already run the provider as a sidecar.
|
|
6
|
+
*
|
|
7
|
+
* Protocol (compatible with bgutil-ytdlp-pot-provider):
|
|
8
|
+
*
|
|
9
|
+
* POST {baseUrl}/get_pot
|
|
10
|
+
* Content-Type: application/json
|
|
11
|
+
* Body: { video_id, visitor_data? }
|
|
12
|
+
* → 200 { po_token, visitor_data, expiration? }
|
|
13
|
+
*
|
|
14
|
+
* If the server returns no token, throws `BotDetected`.
|
|
15
|
+
*/
|
|
16
|
+
export class HttpPoTokenProvider {
|
|
17
|
+
baseUrl;
|
|
18
|
+
timeoutMs;
|
|
19
|
+
fetchImpl;
|
|
20
|
+
ttlMs;
|
|
21
|
+
cache = null;
|
|
22
|
+
signal;
|
|
23
|
+
constructor(opts) {
|
|
24
|
+
if (!opts.baseUrl) {
|
|
25
|
+
throw new Error('HttpPoTokenProvider requires baseUrl');
|
|
26
|
+
}
|
|
27
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, '');
|
|
28
|
+
this.timeoutMs = opts.timeoutMs ?? 30_000;
|
|
29
|
+
const f = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
30
|
+
if (!f) {
|
|
31
|
+
throw new Error('No fetch implementation available');
|
|
32
|
+
}
|
|
33
|
+
this.fetchImpl = f;
|
|
34
|
+
this.ttlMs = opts.ttlMs ?? 12 * 60 * 60 * 1000; // 12h default
|
|
35
|
+
this.signal = opts.signal;
|
|
36
|
+
}
|
|
37
|
+
async generateForVideo(videoId) {
|
|
38
|
+
if (this.cache && this.cache.videoId === videoId && isTokenFresh(this.cache.result)) {
|
|
39
|
+
return this.cache.result;
|
|
40
|
+
}
|
|
41
|
+
const controller = new AbortController();
|
|
42
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
43
|
+
this.signal?.addEventListener('abort', () => controller.abort(), { once: true });
|
|
44
|
+
try {
|
|
45
|
+
const response = await this.fetchImpl(`${this.baseUrl}/get_pot`, {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
headers: { 'Content-Type': 'application/json' },
|
|
48
|
+
body: JSON.stringify({ video_id: videoId }),
|
|
49
|
+
signal: controller.signal,
|
|
50
|
+
});
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
throw new BotDetected(videoId);
|
|
53
|
+
}
|
|
54
|
+
const data = (await response.json());
|
|
55
|
+
if (!data.po_token || !data.visitor_data) {
|
|
56
|
+
throw new BotDetected(videoId);
|
|
57
|
+
}
|
|
58
|
+
const expiresAt = parseExpiration(data.expiration, this.ttlMs);
|
|
59
|
+
const result = {
|
|
60
|
+
poToken: data.po_token,
|
|
61
|
+
visitorData: data.visitor_data,
|
|
62
|
+
expiresAt,
|
|
63
|
+
};
|
|
64
|
+
this.cache = { videoId, result };
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
if (err instanceof BotDetected)
|
|
69
|
+
throw err;
|
|
70
|
+
// Re-throw AbortError directly so tests / callers can distinguish
|
|
71
|
+
// timeout from other failures.
|
|
72
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
73
|
+
throw new Error(`PoToken request timed out for video "${videoId}"`);
|
|
74
|
+
}
|
|
75
|
+
// Wrap network errors as BotDetected since they likely indicate the
|
|
76
|
+
// provider is down or unreachable.
|
|
77
|
+
if (process.env['DEBUG_POT']) {
|
|
78
|
+
console.error('[HttpPoTokenProvider] fetch failed:', err);
|
|
79
|
+
}
|
|
80
|
+
throw new BotDetected(videoId);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
clearTimeout(timer);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async dispose() {
|
|
87
|
+
this.cache = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function parseExpiration(value, fallbackMs) {
|
|
91
|
+
if (typeof value === 'number') {
|
|
92
|
+
return new Date(value > 1e12 ? value : Date.now() + value);
|
|
93
|
+
}
|
|
94
|
+
if (typeof value === 'string') {
|
|
95
|
+
const parsed = Date.parse(value);
|
|
96
|
+
if (Number.isFinite(parsed))
|
|
97
|
+
return new Date(parsed);
|
|
98
|
+
}
|
|
99
|
+
return new Date(Date.now() + fallbackMs);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=HttpPoTokenProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpPoTokenProvider.js","sourceRoot":"","sources":["../../../src/potoken/HttpPoTokenProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PoTokenProvider, TokenResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Default PoToken provider — always throws.
|
|
4
|
+
*
|
|
5
|
+
* This preserves Python-library behavior: ANDROID InnerTube is used as
|
|
6
|
+
* the primary path, and PoToken is only required if the user explicitly
|
|
7
|
+
* opts in via a real provider.
|
|
8
|
+
*/
|
|
9
|
+
export declare class NoopPoTokenProvider implements PoTokenProvider {
|
|
10
|
+
generateForVideo(_videoId: string): Promise<TokenResult>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=NoopPoTokenProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoopPoTokenProvider.d.ts","sourceRoot":"","sources":["../../../src/potoken/NoopPoTokenProvider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE/D;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACnD,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAG/D"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PoTokenRequired } from '../errors/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Default PoToken provider — always throws.
|
|
4
|
+
*
|
|
5
|
+
* This preserves Python-library behavior: ANDROID InnerTube is used as
|
|
6
|
+
* the primary path, and PoToken is only required if the user explicitly
|
|
7
|
+
* opts in via a real provider.
|
|
8
|
+
*/
|
|
9
|
+
export class NoopPoTokenProvider {
|
|
10
|
+
async generateForVideo(_videoId) {
|
|
11
|
+
throw new PoTokenRequired(_videoId);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=NoopPoTokenProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoopPoTokenProvider.js","sourceRoot":"","sources":["../../../src/potoken/NoopPoTokenProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrD;;;;;;GAMG;AACH,MAAM,OAAO,mBAAmB;IAC9B,KAAK,CAAC,gBAAgB,CAAC,QAAgB;QACrC,MAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;CACF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory cache for YouTube's base.js player script.
|
|
3
|
+
*
|
|
4
|
+
* base.js (~2.5MB minified) changes occasionally; we cache it for
|
|
5
|
+
* `ttlMs` (default 5 minutes) to avoid repeated downloads. The AutoPoTokenProvider
|
|
6
|
+
* owns the cache.
|
|
7
|
+
*/
|
|
8
|
+
export interface BaseScriptCacheOptions {
|
|
9
|
+
/** Time-to-live in ms (default 5 minutes). */
|
|
10
|
+
ttlMs?: number;
|
|
11
|
+
/** Custom fetch implementation. */
|
|
12
|
+
fetchImpl?: typeof fetch;
|
|
13
|
+
}
|
|
14
|
+
export declare class BaseScriptCache {
|
|
15
|
+
private readonly ttlMs;
|
|
16
|
+
private readonly fetchImpl;
|
|
17
|
+
private cached;
|
|
18
|
+
constructor(opts?: BaseScriptCacheOptions);
|
|
19
|
+
/**
|
|
20
|
+
* Get base.js content. Re-downloads when cache is stale or missing.
|
|
21
|
+
*/
|
|
22
|
+
get(baseJsUrl: string): Promise<string>;
|
|
23
|
+
/** Force the next `get()` to re-download. */
|
|
24
|
+
invalidate(): void;
|
|
25
|
+
/** Inspect cache state (for tests). */
|
|
26
|
+
isFresh(): boolean;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=baseScriptCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseScriptCache.d.ts","sourceRoot":"","sources":["../../../src/potoken/baseScriptCache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,MAAM,CAAuD;gBAEzD,IAAI,GAAE,sBAA2B;IAS7C;;OAEG;IACG,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAa7C,6CAA6C;IAC7C,UAAU,IAAI,IAAI;IAIlB,uCAAuC;IACvC,OAAO,IAAI,OAAO;CAGnB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export class BaseScriptCache {
|
|
2
|
+
ttlMs;
|
|
3
|
+
fetchImpl;
|
|
4
|
+
cached = null;
|
|
5
|
+
constructor(opts = {}) {
|
|
6
|
+
this.ttlMs = opts.ttlMs ?? 5 * 60 * 1000;
|
|
7
|
+
const f = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
8
|
+
if (!f) {
|
|
9
|
+
throw new Error('No fetch implementation available');
|
|
10
|
+
}
|
|
11
|
+
this.fetchImpl = f;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get base.js content. Re-downloads when cache is stale or missing.
|
|
15
|
+
*/
|
|
16
|
+
async get(baseJsUrl) {
|
|
17
|
+
if (this.cached && Date.now() - this.cached.fetchedAt < this.ttlMs) {
|
|
18
|
+
return this.cached.content;
|
|
19
|
+
}
|
|
20
|
+
const response = await this.fetchImpl(baseJsUrl);
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`Failed to fetch base.js: ${response.status} ${response.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
const content = await response.text();
|
|
25
|
+
this.cached = { content, fetchedAt: Date.now() };
|
|
26
|
+
return content;
|
|
27
|
+
}
|
|
28
|
+
/** Force the next `get()` to re-download. */
|
|
29
|
+
invalidate() {
|
|
30
|
+
this.cached = null;
|
|
31
|
+
}
|
|
32
|
+
/** Inspect cache state (for tests). */
|
|
33
|
+
isFresh() {
|
|
34
|
+
return this.cached !== null && Date.now() - this.cached.fetchedAt < this.ttlMs;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=baseScriptCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseScriptCache.js","sourceRoot":"","sources":["../../../src/potoken/baseScriptCache.ts"],"names":[],"mappings":"AAcA,MAAM,OAAO,eAAe;IACT,KAAK,CAAS;IACd,SAAS,CAAe;IACjC,MAAM,GAAkD,IAAI,CAAC;IAErE,YAAY,OAA+B,EAAE;QAC3C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QACzC,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9D,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACnE,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;QAC7B,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACxF,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACjD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,6CAA6C;IAC7C,UAAU;QACR,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,uCAAuC;IACvC,OAAO;QACL,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC;IACjF,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { NoopPoTokenProvider } from './NoopPoTokenProvider.js';
|
|
2
|
+
export { HttpPoTokenProvider } from './HttpPoTokenProvider.js';
|
|
3
|
+
export type { HttpPoTokenProviderOptions } from './HttpPoTokenProvider.js';
|
|
4
|
+
export { AutoPoTokenProvider } from './AutoPoTokenProvider.js';
|
|
5
|
+
export type { AutoPoTokenProviderOptions } from './AutoPoTokenProvider.js';
|
|
6
|
+
export { BaseScriptCache } from './baseScriptCache.js';
|
|
7
|
+
export type { BaseScriptCacheOptions } from './baseScriptCache.js';
|
|
8
|
+
export { isTokenFresh } from './types.js';
|
|
9
|
+
export type { PoTokenProvider, TokenResult } from './types.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/potoken/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { NoopPoTokenProvider } from './NoopPoTokenProvider.js';
|
|
2
|
+
export { HttpPoTokenProvider } from './HttpPoTokenProvider.js';
|
|
3
|
+
export { AutoPoTokenProvider } from './AutoPoTokenProvider.js';
|
|
4
|
+
export { BaseScriptCache } from './baseScriptCache.js';
|
|
5
|
+
export { isTokenFresh } from './types.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/potoken/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A successful PoToken generation result.
|
|
3
|
+
*/
|
|
4
|
+
export interface TokenResult {
|
|
5
|
+
/** The PoToken (`identityToken`) string. */
|
|
6
|
+
readonly poToken: string;
|
|
7
|
+
/** The visitorData (`VISITOR_DATA` cookie value). */
|
|
8
|
+
readonly visitorData: string;
|
|
9
|
+
/**
|
|
10
|
+
* Wall-clock time after which this token should be considered expired.
|
|
11
|
+
* Providers may set this conservatively (e.g. 12h).
|
|
12
|
+
*/
|
|
13
|
+
readonly expiresAt: Date;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A pluggable PoToken provider.
|
|
17
|
+
*
|
|
18
|
+
* Implementations include:
|
|
19
|
+
* - {@link NoopPoTokenProvider} (default; throws PoTokenRequired)
|
|
20
|
+
* - {@link HttpPoTokenProvider} (calls an external HTTP endpoint)
|
|
21
|
+
* - {@link AutoPoTokenProvider} (self-contained via bgutils-js)
|
|
22
|
+
*/
|
|
23
|
+
export interface PoTokenProvider {
|
|
24
|
+
/**
|
|
25
|
+
* Generate (or return a cached) PoToken for the given video.
|
|
26
|
+
*
|
|
27
|
+
* Providers are responsible for caching; the facade does not cache
|
|
28
|
+
* results across calls.
|
|
29
|
+
*
|
|
30
|
+
* @throws if generation fails irrecoverably
|
|
31
|
+
*/
|
|
32
|
+
generateForVideo(videoId: string): Promise<TokenResult>;
|
|
33
|
+
/** Optional cleanup (e.g. close HTTP clients, release timers). */
|
|
34
|
+
dispose?(): Promise<void> | void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Internal: returns true if a token is still fresh (with a safety margin).
|
|
38
|
+
*/
|
|
39
|
+
export declare function isTokenFresh(result: TokenResult, safetyMarginMs?: number): boolean;
|
|
40
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/potoken/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,qDAAqD;IACrD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAExD,kEAAkE;IAClE,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,GAAE,MAAe,GAAG,OAAO,CAE1F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/potoken/types.ts"],"names":[],"mappings":"AAsCA;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmB,EAAE,iBAAyB,MAAM;IAC/E,OAAO,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitize a piece of HTML-formatted transcript text into plain text
|
|
3
|
+
* with HTML entities decoded.
|
|
4
|
+
*
|
|
5
|
+
* YouTube occasionally double-encodes entities (`&#39;` instead of `'`),
|
|
6
|
+
* so we decode repeatedly until the string stabilises (capped at 5 passes
|
|
7
|
+
* to defend against pathological cases).
|
|
8
|
+
*
|
|
9
|
+
* @param raw raw `<text>` inner content from the timedtext XML
|
|
10
|
+
* @param preserveFormatting when true, retain formatting tags listed above
|
|
11
|
+
*/
|
|
12
|
+
export declare function sanitizeTranscriptText(raw: string, preserveFormatting?: boolean): string;
|
|
13
|
+
/**
|
|
14
|
+
* Decode HTML entities only (no tag stripping). Useful for diagnostics.
|
|
15
|
+
*/
|
|
16
|
+
export declare function decodeHtmlEntities(text: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Tags retained when `preserveFormatting=true`. Exposed for tests.
|
|
19
|
+
*/
|
|
20
|
+
export declare const PRESERVED_FORMATTING_TAGS: readonly string[];
|
|
21
|
+
//# sourceMappingURL=htmlSanitizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"htmlSanitizer.d.ts","sourceRoot":"","sources":["../../../src/util/htmlSanitizer.ts"],"names":[],"mappings":"AAyCA;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,kBAAkB,GAAE,OAAe,GAAG,MAAM,CAS/F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EAAoB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import he from 'he';
|
|
2
|
+
/**
|
|
3
|
+
* HTML / formatting helpers for transcript text.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the Python library's `_TranscriptParser`:
|
|
6
|
+
* - `he.decode` (equivalent to Python's `html.unescape`) for entity resolution
|
|
7
|
+
* - `preserveFormatting=true` keeps a small set of formatting tags and
|
|
8
|
+
* strips everything else (via negative-lookahead regex from Python source)
|
|
9
|
+
* - `preserveFormatting=false` strips every tag
|
|
10
|
+
*/
|
|
11
|
+
const FORMATTING_TAGS = [
|
|
12
|
+
'strong',
|
|
13
|
+
'em',
|
|
14
|
+
'b',
|
|
15
|
+
'i',
|
|
16
|
+
'mark',
|
|
17
|
+
'small',
|
|
18
|
+
'del',
|
|
19
|
+
'ins',
|
|
20
|
+
'sub',
|
|
21
|
+
'sup',
|
|
22
|
+
];
|
|
23
|
+
/** Regex that strips all HTML tags. */
|
|
24
|
+
const STRIP_ALL_TAGS_REGEX = /<[^>]*>/g;
|
|
25
|
+
/**
|
|
26
|
+
* Regex that strips every tag EXCEPT a small set of formatting tags.
|
|
27
|
+
*
|
|
28
|
+
* Constructed once at module load. Note: `[^>]*?` keeps each match confined
|
|
29
|
+
* to a single tag, so adjacent tags (e.g. `<font>x</font>`) are stripped
|
|
30
|
+
* independently rather than swallowed together.
|
|
31
|
+
*/
|
|
32
|
+
const STRIP_BUT_FORMATTING_REGEX = (() => {
|
|
33
|
+
const alt = FORMATTING_TAGS.join('|');
|
|
34
|
+
// Negative lookahead: don't match open/close of the formatting tags.
|
|
35
|
+
return new RegExp(`<\\/?(?!\\/?(${alt})\\b)[^>]*>`, 'gi');
|
|
36
|
+
})();
|
|
37
|
+
/**
|
|
38
|
+
* Sanitize a piece of HTML-formatted transcript text into plain text
|
|
39
|
+
* with HTML entities decoded.
|
|
40
|
+
*
|
|
41
|
+
* YouTube occasionally double-encodes entities (`&#39;` instead of `'`),
|
|
42
|
+
* so we decode repeatedly until the string stabilises (capped at 5 passes
|
|
43
|
+
* to defend against pathological cases).
|
|
44
|
+
*
|
|
45
|
+
* @param raw raw `<text>` inner content from the timedtext XML
|
|
46
|
+
* @param preserveFormatting when true, retain formatting tags listed above
|
|
47
|
+
*/
|
|
48
|
+
export function sanitizeTranscriptText(raw, preserveFormatting = false) {
|
|
49
|
+
let unescaped = raw;
|
|
50
|
+
for (let i = 0; i < 5; i++) {
|
|
51
|
+
const next = he.decode(unescaped);
|
|
52
|
+
if (next === unescaped)
|
|
53
|
+
break;
|
|
54
|
+
unescaped = next;
|
|
55
|
+
}
|
|
56
|
+
const regex = preserveFormatting ? STRIP_BUT_FORMATTING_REGEX : STRIP_ALL_TAGS_REGEX;
|
|
57
|
+
return unescaped.replace(regex, '');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Decode HTML entities only (no tag stripping). Useful for diagnostics.
|
|
61
|
+
*/
|
|
62
|
+
export function decodeHtmlEntities(text) {
|
|
63
|
+
return he.decode(text);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Tags retained when `preserveFormatting=true`. Exposed for tests.
|
|
67
|
+
*/
|
|
68
|
+
export const PRESERVED_FORMATTING_TAGS = FORMATTING_TAGS;
|
|
69
|
+
//# sourceMappingURL=htmlSanitizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"htmlSanitizer.js","sourceRoot":"","sources":["../../../src/util/htmlSanitizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB;;;;;;;;GAQG;AAEH,MAAM,eAAe,GAAG;IACtB,QAAQ;IACR,IAAI;IACJ,GAAG;IACH,GAAG;IACH,MAAM;IACN,OAAO;IACP,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;CACG,CAAC;AAEX,uCAAuC;AACvC,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;GAMG;AACH,MAAM,0BAA0B,GAAW,CAAC,GAAG,EAAE;IAC/C,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtC,qEAAqE;IACrE,OAAO,IAAI,MAAM,CAAC,gBAAgB,GAAG,aAAa,EAAE,IAAI,CAAC,CAAC;AAC5D,CAAC,CAAC,EAAE,CAAC;AAEL;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW,EAAE,qBAA8B,KAAK;IACrF,IAAI,SAAS,GAAG,GAAG,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClC,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM;QAC9B,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,kBAAkB,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,oBAAoB,CAAC;IACrF,OAAO,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAsB,eAAe,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsed proxy URL.
|
|
3
|
+
*/
|
|
4
|
+
export interface ParsedProxyUrl {
|
|
5
|
+
/** Protocol: http | https | socks | socks4 | socks5 */
|
|
6
|
+
readonly protocol: string;
|
|
7
|
+
/** Username, if provided. */
|
|
8
|
+
readonly username: string | undefined;
|
|
9
|
+
/** Password, if provided. */
|
|
10
|
+
readonly password: string | undefined;
|
|
11
|
+
/** Hostname (no port). */
|
|
12
|
+
readonly host: string;
|
|
13
|
+
/** Port, if provided. */
|
|
14
|
+
readonly port: number | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse a proxy URL like `http://user:pass@host:1080` or `socks5://host:1080`.
|
|
18
|
+
*
|
|
19
|
+
* Returns `null` if the URL is malformed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseProxyUrl(url: string): ParsedProxyUrl | null;
|
|
22
|
+
//# sourceMappingURL=proxyUrl.d.ts.map
|