googlevideo 3.0.0 → 4.0.1
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/README.md +93 -45
- package/dist/protos/generated/misc/common.d.ts +180 -6
- package/dist/protos/generated/misc/common.js +282 -19
- package/dist/protos/generated/misc/common.js.map +1 -0
- package/dist/protos/generated/video_streaming/buffered_range.d.ts +10 -10
- package/dist/protos/generated/video_streaming/buffered_range.js +20 -19
- package/dist/protos/generated/video_streaming/buffered_range.js.map +1 -0
- package/dist/protos/generated/video_streaming/client_abr_state.d.ts +22 -11
- package/dist/protos/generated/video_streaming/client_abr_state.js +133 -50
- package/dist/protos/generated/video_streaming/client_abr_state.js.map +1 -0
- package/dist/protos/generated/video_streaming/crypto_params.d.ts +2 -7
- package/dist/protos/generated/video_streaming/crypto_params.js +1 -7
- package/dist/protos/generated/video_streaming/crypto_params.js.map +1 -0
- package/dist/protos/generated/video_streaming/format_initialization_metadata.d.ts +6 -6
- package/dist/protos/generated/video_streaming/format_initialization_metadata.js +32 -21
- package/dist/protos/generated/video_streaming/format_initialization_metadata.js.map +1 -0
- package/dist/protos/generated/video_streaming/format_selection_config.d.ts +12 -0
- package/dist/protos/generated/video_streaming/format_selection_config.js +68 -0
- package/dist/protos/generated/video_streaming/format_selection_config.js.map +1 -0
- package/dist/protos/generated/video_streaming/{encrypted_player_request.d.ts → innertube_request.d.ts} +11 -6
- package/dist/protos/generated/video_streaming/{encrypted_player_request.js → innertube_request.js} +64 -20
- package/dist/protos/generated/video_streaming/innertube_request.js.map +1 -0
- package/dist/protos/generated/video_streaming/live_metadata.d.ts +8 -5
- package/dist/protos/generated/video_streaming/live_metadata.js +57 -26
- package/dist/protos/generated/video_streaming/live_metadata.js.map +1 -0
- package/dist/protos/generated/video_streaming/media_capabilities.js +1 -0
- package/dist/protos/generated/video_streaming/media_capabilities.js.map +1 -0
- package/dist/protos/generated/video_streaming/media_header.d.ts +5 -10
- package/dist/protos/generated/video_streaming/media_header.js +27 -23
- package/dist/protos/generated/video_streaming/media_header.js.map +1 -0
- package/dist/protos/generated/video_streaming/next_request_policy.d.ts +3 -0
- package/dist/protos/generated/video_streaming/next_request_policy.js +31 -0
- package/dist/protos/generated/video_streaming/next_request_policy.js.map +1 -0
- package/dist/protos/generated/video_streaming/onesie_header.d.ts +7 -7
- package/dist/protos/generated/video_streaming/onesie_header.js +15 -14
- package/dist/protos/generated/video_streaming/onesie_header.js.map +1 -0
- package/dist/protos/generated/video_streaming/onesie_header_type.d.ts +9 -23
- package/dist/protos/generated/video_streaming/onesie_header_type.js +16 -30
- package/dist/protos/generated/video_streaming/onesie_header_type.js.map +1 -0
- package/dist/protos/generated/video_streaming/{onesie_player_request.d.ts → onesie_innertube_request.d.ts} +2 -2
- package/dist/protos/generated/video_streaming/{onesie_player_request.js → onesie_innertube_request.js} +5 -4
- package/dist/protos/generated/video_streaming/onesie_innertube_request.js.map +1 -0
- package/dist/protos/generated/video_streaming/onesie_innertube_response.d.ts +15 -0
- package/dist/protos/generated/video_streaming/{onesie_player_response.js → onesie_innertube_response.js} +5 -22
- package/dist/protos/generated/video_streaming/onesie_innertube_response.js.map +1 -0
- package/dist/protos/generated/video_streaming/onesie_proxy_status.d.ts +18 -0
- package/dist/protos/generated/video_streaming/onesie_proxy_status.js +25 -0
- package/dist/protos/generated/video_streaming/onesie_proxy_status.js.map +1 -0
- package/dist/protos/generated/video_streaming/onesie_request.d.ts +6 -3
- package/dist/protos/generated/video_streaming/onesie_request.js +17 -5
- package/dist/protos/generated/video_streaming/onesie_request.js.map +1 -0
- package/dist/protos/generated/video_streaming/playback_cookie.d.ts +2 -2
- package/dist/protos/generated/video_streaming/playback_cookie.js +5 -4
- package/dist/protos/generated/video_streaming/playback_cookie.js.map +1 -0
- package/dist/protos/generated/video_streaming/playback_start_policy.js +1 -0
- package/dist/protos/generated/video_streaming/playback_start_policy.js.map +1 -0
- package/dist/protos/generated/video_streaming/reload_player_response.d.ts +14 -0
- package/dist/protos/generated/video_streaming/reload_player_response.js +73 -0
- package/dist/protos/generated/video_streaming/reload_player_response.js.map +1 -0
- package/dist/protos/generated/video_streaming/request_cancellation_policy.js +1 -0
- package/dist/protos/generated/video_streaming/request_cancellation_policy.js.map +1 -0
- package/dist/protos/generated/video_streaming/request_identifier.d.ts +10 -0
- package/dist/protos/generated/video_streaming/request_identifier.js +41 -0
- package/dist/protos/generated/video_streaming/request_identifier.js.map +1 -0
- package/dist/protos/generated/video_streaming/sabr_context_sending_policy.d.ts +12 -0
- package/dist/protos/generated/video_streaming/sabr_context_sending_policy.js +86 -0
- package/dist/protos/generated/video_streaming/sabr_context_sending_policy.js.map +1 -0
- package/dist/protos/generated/video_streaming/sabr_context_update.d.ts +48 -0
- package/dist/protos/generated/video_streaming/sabr_context_update.js +242 -0
- package/dist/protos/generated/video_streaming/sabr_context_update.js.map +1 -0
- package/dist/protos/generated/video_streaming/sabr_error.js +1 -0
- package/dist/protos/generated/video_streaming/sabr_error.js.map +1 -0
- package/dist/protos/generated/video_streaming/sabr_redirect.js +1 -0
- package/dist/protos/generated/video_streaming/sabr_redirect.js.map +1 -0
- package/dist/protos/generated/video_streaming/snackbar_message.d.ts +10 -0
- package/dist/protos/generated/video_streaming/snackbar_message.js +41 -0
- package/dist/protos/generated/video_streaming/snackbar_message.js.map +1 -0
- package/dist/protos/generated/video_streaming/stream_protection_status.d.ts +1 -1
- package/dist/protos/generated/video_streaming/stream_protection_status.js +5 -4
- package/dist/protos/generated/video_streaming/stream_protection_status.js.map +1 -0
- package/dist/protos/generated/video_streaming/streamer_context.d.ts +11 -11
- package/dist/protos/generated/video_streaming/streamer_context.js +32 -32
- package/dist/protos/generated/video_streaming/streamer_context.js.map +1 -0
- package/dist/protos/generated/video_streaming/time_range.d.ts +2 -2
- package/dist/protos/generated/video_streaming/time_range.js +8 -7
- package/dist/protos/generated/video_streaming/time_range.js.map +1 -0
- package/dist/protos/generated/video_streaming/ump_part_id.d.ts +58 -0
- package/dist/protos/generated/video_streaming/ump_part_id.js +89 -0
- package/dist/protos/generated/video_streaming/ump_part_id.js.map +1 -0
- package/dist/protos/generated/video_streaming/video_playback_abr_request.d.ts +20 -21
- package/dist/protos/generated/video_streaming/video_playback_abr_request.js +48 -86
- package/dist/protos/generated/video_streaming/video_playback_abr_request.js.map +1 -0
- package/dist/src/core/{ChunkedDataBuffer.d.ts → CompositeBuffer.d.ts} +11 -8
- package/dist/src/core/{ChunkedDataBuffer.js → CompositeBuffer.js} +35 -27
- package/dist/src/core/CompositeBuffer.js.map +1 -0
- package/dist/src/core/SabrStream.d.ts +356 -0
- package/dist/src/core/SabrStream.js +958 -0
- package/dist/src/core/SabrStream.js.map +1 -0
- package/dist/src/core/SabrStreamingAdapter.d.ts +158 -0
- package/dist/src/core/SabrStreamingAdapter.js +496 -0
- package/dist/src/core/SabrStreamingAdapter.js.map +1 -0
- package/dist/src/core/SabrUmpProcessor.d.ts +53 -0
- package/dist/src/core/SabrUmpProcessor.js +234 -0
- package/dist/src/core/SabrUmpProcessor.js.map +1 -0
- package/dist/src/core/{UMP.d.ts → UmpReader.d.ts} +9 -10
- package/dist/src/core/{UMP.js → UmpReader.js} +36 -36
- package/dist/src/core/UmpReader.js.map +1 -0
- package/dist/src/core/UmpWriter.d.ts +19 -0
- package/dist/src/core/UmpWriter.js +59 -0
- package/dist/src/core/UmpWriter.js.map +1 -0
- package/dist/src/exports/protos.d.ts +5 -0
- package/dist/src/exports/protos.js +6 -0
- package/dist/src/exports/protos.js.map +1 -0
- package/dist/src/exports/sabr-stream.d.ts +6 -0
- package/dist/src/exports/sabr-stream.js +6 -0
- package/dist/src/exports/sabr-stream.js.map +1 -0
- package/dist/src/exports/sabr-streaming-adapter.d.ts +8 -0
- package/dist/src/exports/sabr-streaming-adapter.js +8 -0
- package/dist/src/exports/sabr-streaming-adapter.js.map +1 -0
- package/dist/src/exports/ump.d.ts +7 -0
- package/dist/src/exports/ump.js +8 -0
- package/dist/src/exports/ump.js.map +1 -0
- package/dist/src/exports/utils.d.ts +5 -0
- package/dist/src/exports/utils.js +6 -0
- package/dist/src/exports/utils.js.map +1 -0
- package/dist/src/types/sabrStreamTypes.d.ts +102 -0
- package/dist/src/types/sabrStreamTypes.js +2 -0
- package/dist/src/types/sabrStreamTypes.js.map +1 -0
- package/dist/src/types/sabrStreamingAdapterTypes.d.ts +93 -0
- package/dist/src/types/sabrStreamingAdapterTypes.js +2 -0
- package/dist/src/types/sabrStreamingAdapterTypes.js.map +1 -0
- package/dist/src/types/shared.d.ts +64 -0
- package/dist/src/types/shared.js +2 -0
- package/dist/src/types/shared.js.map +1 -0
- package/dist/src/utils/CacheManager.d.ts +32 -0
- package/dist/src/utils/CacheManager.js +131 -0
- package/dist/src/utils/CacheManager.js.map +1 -0
- package/dist/src/utils/EventEmitterLike.d.ts +5 -0
- package/dist/src/utils/EventEmitterLike.js +51 -10
- package/dist/src/utils/EventEmitterLike.js.map +1 -0
- package/dist/src/utils/Logger.d.ts +43 -0
- package/dist/src/utils/Logger.js +93 -0
- package/dist/src/utils/Logger.js.map +1 -0
- package/dist/src/utils/Protos.d.ts +20 -13
- package/dist/src/utils/Protos.js +21 -13
- package/dist/src/utils/Protos.js.map +1 -0
- package/dist/src/utils/RequestMetadataManager.d.ts +15 -0
- package/dist/src/utils/RequestMetadataManager.js +48 -0
- package/dist/src/utils/RequestMetadataManager.js.map +1 -0
- package/dist/src/utils/formatKeyUtils.d.ts +45 -0
- package/dist/src/utils/formatKeyUtils.js +77 -0
- package/dist/src/utils/formatKeyUtils.js.map +1 -0
- package/dist/src/utils/index.d.ts +5 -3
- package/dist/src/utils/index.js +6 -2
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/sabrStreamUtils.d.ts +28 -0
- package/dist/src/utils/sabrStreamUtils.js +76 -0
- package/dist/src/utils/sabrStreamUtils.js.map +1 -0
- package/dist/src/utils/shared.d.ts +55 -0
- package/dist/src/utils/shared.js +120 -0
- package/dist/src/utils/shared.js.map +1 -0
- package/package.json +40 -12
- package/dist/protos/generated/video_streaming/onesie_player_response.d.ts +0 -31
- package/dist/protos/generated/video_streaming/proxy_status.d.ts +0 -14
- package/dist/protos/generated/video_streaming/proxy_status.js +0 -21
- package/dist/src/core/ServerAbrStream.d.ts +0 -39
- package/dist/src/core/ServerAbrStream.js +0 -259
- package/dist/src/core/index.d.ts +0 -3
- package/dist/src/core/index.js +0 -3
- package/dist/src/index.d.ts +0 -4
- package/dist/src/index.js +0 -4
- package/dist/src/utils/helpers.d.ts +0 -63
- package/dist/src/utils/helpers.js +0 -101
- package/dist/src/utils/types.d.ts +0 -65
- package/dist/src/utils/types.js +0 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export const MAX_INT32_VALUE = 2147483647;
|
|
2
|
+
export const EnabledTrackTypes = {
|
|
3
|
+
VIDEO_AND_AUDIO: 0, 0: "VIDEO_AND_AUDIO",
|
|
4
|
+
AUDIO_ONLY: 1, 1: "AUDIO_ONLY",
|
|
5
|
+
VIDEO_ONLY: 2, 2: "VIDEO_ONLY"
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Determines if a given URL is a Google video URL, specifically for YouTube or SABR-related content.
|
|
9
|
+
*
|
|
10
|
+
* @param url - The URL to check.
|
|
11
|
+
*
|
|
12
|
+
* The function checks the following conditions:
|
|
13
|
+
* 1. If the URL starts with the `sabr://` protocol, it is considered a Google video URL.
|
|
14
|
+
* 2. If the URL ends with `/videoplayback`, it parses the query parameters to check for specific keys
|
|
15
|
+
* (`source=youtube`, `sabr`, `lsig`, or `expire`) that indicate a Google video URL.
|
|
16
|
+
* 3. If the URL contains `/videoplayback/` (e.g., for live or post-live content), it checks the path
|
|
17
|
+
* segments for specific keywords (`videoplayback`, `sabr`, `lsig`, or `expire`).
|
|
18
|
+
*/
|
|
19
|
+
export function isGoogleVideoURL(url) {
|
|
20
|
+
if (url.startsWith('sabr://')) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
const urlParts = url.split('?');
|
|
24
|
+
const urlPart = urlParts[0];
|
|
25
|
+
const queryPart = urlParts[1] || '';
|
|
26
|
+
if (urlPart.endsWith('/videoplayback')) {
|
|
27
|
+
const params = new URLSearchParams(queryPart);
|
|
28
|
+
if (params.get('source') === 'youtube' || params.has('sabr') || params.has('lsig') || params.has('expire')) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (urlPart.includes('/videoplayback/')) { // For live content, post-live, etc.
|
|
33
|
+
const pathParts = urlPart.split('/');
|
|
34
|
+
return ['videoplayback', 'sabr', 'lsig', 'expire'].some((part) => pathParts.includes(part));
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parses the Range header value to extract the start and end byte positions.
|
|
40
|
+
* @param rangeHeaderValue
|
|
41
|
+
*/
|
|
42
|
+
export function parseRangeHeader(rangeHeaderValue) {
|
|
43
|
+
if (!rangeHeaderValue)
|
|
44
|
+
return undefined;
|
|
45
|
+
const parts = rangeHeaderValue.split('=')[1]?.split('-');
|
|
46
|
+
if (parts?.length) {
|
|
47
|
+
const start = Number(parts[0]);
|
|
48
|
+
const end = Number(parts[1]);
|
|
49
|
+
return { start, end };
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Converts a Uint8Array to a Base64 string.
|
|
55
|
+
* @param u8
|
|
56
|
+
*/
|
|
57
|
+
export function u8ToBase64(u8) {
|
|
58
|
+
return btoa(String.fromCharCode.apply(null, Array.from(u8)));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Converts a Base64 string to a Uint8Array.
|
|
62
|
+
* @param base64
|
|
63
|
+
*/
|
|
64
|
+
export function base64ToU8(base64) {
|
|
65
|
+
const standard_base64 = base64.replace(/-/g, '+').replace(/_/g, '/');
|
|
66
|
+
const padded_base64 = standard_base64.padEnd(standard_base64.length + (4 - standard_base64.length % 4) % 4, '=');
|
|
67
|
+
return new Uint8Array(atob(padded_base64).split('').map((char) => char.charCodeAt(0)));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Concatenates multiple Uint8Array chunks into a single Uint8Array.
|
|
71
|
+
* @param chunks
|
|
72
|
+
*/
|
|
73
|
+
export function concatenateChunks(chunks) {
|
|
74
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
75
|
+
const result = new Uint8Array(totalLength);
|
|
76
|
+
let offset = 0;
|
|
77
|
+
for (const chunk of chunks) {
|
|
78
|
+
result.set(chunk, offset);
|
|
79
|
+
offset += chunk.length;
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Converts a FormatStream object to a SabrFormat object.
|
|
85
|
+
* @param formatStream
|
|
86
|
+
*/
|
|
87
|
+
export function buildSabrFormat(formatStream) {
|
|
88
|
+
return {
|
|
89
|
+
itag: formatStream.itag,
|
|
90
|
+
lastModified: parseInt(formatStream.last_modified_ms || formatStream.lastModified || '0'),
|
|
91
|
+
xtags: formatStream.xtags,
|
|
92
|
+
width: formatStream.width,
|
|
93
|
+
height: formatStream.height,
|
|
94
|
+
mimeType: formatStream.mime_type || formatStream.mimeType,
|
|
95
|
+
audioQuality: formatStream.audio_quality || formatStream.audioQuality,
|
|
96
|
+
bitrate: formatStream.bitrate,
|
|
97
|
+
averageBitrate: formatStream.average_bitrate || formatStream.averageBitrate,
|
|
98
|
+
quality: formatStream.quality,
|
|
99
|
+
qualityLabel: formatStream.quality_label || formatStream.qualityLabel,
|
|
100
|
+
audioTrackId: formatStream.audio_track?.id || formatStream.audioTrackId,
|
|
101
|
+
approxDurationMs: formatStream.approx_duration_ms || parseInt(formatStream.approxDurationMs || '0'),
|
|
102
|
+
contentLength: parseInt(formatStream.contentLength || '0') || formatStream.content_length,
|
|
103
|
+
// YouTube.js-specific properties.
|
|
104
|
+
isDrc: formatStream.is_drc,
|
|
105
|
+
isAutoDubbed: formatStream.is_auto_dubbed,
|
|
106
|
+
isDescriptive: formatStream.is_descriptive,
|
|
107
|
+
isDubbed: formatStream.is_dubbed,
|
|
108
|
+
language: formatStream.language,
|
|
109
|
+
isOriginal: formatStream.is_original,
|
|
110
|
+
isSecondary: formatStream.is_secondary
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Returns a promise that resolves after a specified number of milliseconds.
|
|
115
|
+
* @param ms - The number of milliseconds to wait.
|
|
116
|
+
*/
|
|
117
|
+
export function wait(ms) {
|
|
118
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/utils/shared.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "googlevideo",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A
|
|
3
|
+
"version": "4.0.1",
|
|
4
|
+
"description": "A collection of modules for working with YouTube's proprietary video streaming protocols (UMP/SABR).",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"types": "./dist/src/index.d.ts",
|
|
8
8
|
"module": "./dist/src/index.js",
|
|
9
9
|
"scripts": {
|
|
10
|
-
"watch": "npx
|
|
10
|
+
"watch": "npx tspc --watch",
|
|
11
11
|
"lint": "npx eslint ./src/**/*.ts",
|
|
12
12
|
"lint:fix": "npx eslint --fix ./src/**/*.ts",
|
|
13
13
|
"clean": "npx rimraf ./dist ./protos/generated",
|
|
14
14
|
"build": "npm run clean && npm run lint && npm run build:proto && npm run build:esm",
|
|
15
|
-
"build:esm": "npx
|
|
15
|
+
"build:esm": "npx tspc",
|
|
16
16
|
"build:proto": "node ./dev-scripts/generate-proto.mjs",
|
|
17
|
+
"build:docs": "typedoc",
|
|
18
|
+
"test": "vitest run --reporter verbose",
|
|
19
|
+
"test:watch": "vitest",
|
|
17
20
|
"prepare": "npm run build"
|
|
18
21
|
},
|
|
19
22
|
"author": "LuanRT <luan.lrt4@gmail.com> (https://github.com/LuanRT)",
|
|
@@ -28,12 +31,33 @@
|
|
|
28
31
|
],
|
|
29
32
|
"license": "MIT",
|
|
30
33
|
"exports": {
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
"./ump": {
|
|
35
|
+
"types": "./dist/src/exports/ump.d.ts",
|
|
36
|
+
"import": "./dist/src/exports/ump.js",
|
|
37
|
+
"default": "./dist/src/exports/ump.js"
|
|
38
|
+
},
|
|
39
|
+
"./sabr-streaming-adapter": {
|
|
40
|
+
"types": "./dist/src/exports/sabr-streaming-adapter.d.ts",
|
|
41
|
+
"import": "./dist/src/exports/sabr-streaming-adapter.js",
|
|
42
|
+
"default": "./dist/src/exports/sabr-streaming-adapter.js"
|
|
43
|
+
},
|
|
44
|
+
"./sabr-stream": {
|
|
45
|
+
"types": "./dist/src/exports/sabr-stream.d.ts",
|
|
46
|
+
"import": "./dist/src/exports/sabr-stream.js",
|
|
47
|
+
"default": "./dist/src/exports/sabr-stream.js"
|
|
48
|
+
},
|
|
49
|
+
"./protos": {
|
|
50
|
+
"types": "./dist/src/exports/protos.d.ts",
|
|
51
|
+
"import": "./dist/src/exports/protos.js",
|
|
52
|
+
"default": "./dist/src/exports/protos.js"
|
|
53
|
+
},
|
|
54
|
+
"./utils": {
|
|
55
|
+
"types": "./dist/src/exports/utils.d.ts",
|
|
56
|
+
"import": "./dist/src/exports/utils.js",
|
|
57
|
+
"default": "./dist/src/exports/utils.js"
|
|
58
|
+
},
|
|
59
|
+
"./shared-types": {
|
|
60
|
+
"types": "./dist/src/types/shared.d.ts"
|
|
37
61
|
}
|
|
38
62
|
},
|
|
39
63
|
"devDependencies": {
|
|
@@ -42,9 +66,13 @@
|
|
|
42
66
|
"@types/eslint__js": "^8.42.3",
|
|
43
67
|
"eslint": "^9.9.0",
|
|
44
68
|
"globals": "^15.9.0",
|
|
69
|
+
"ts-patch": "^3.3.0",
|
|
45
70
|
"ts-proto": "^2.2.0",
|
|
71
|
+
"typedoc": "^0.28.7",
|
|
72
|
+
"typedoc-plugin-markdown": "^4.7.1",
|
|
46
73
|
"typescript": "^5.5.4",
|
|
47
|
-
"typescript-eslint": "^8.2.0"
|
|
74
|
+
"typescript-eslint": "^8.2.0",
|
|
75
|
+
"vitest": "^3.2.4"
|
|
48
76
|
},
|
|
49
77
|
"dependencies": {
|
|
50
78
|
"@bufbuild/protobuf": "^2.0.0"
|
|
@@ -57,4 +85,4 @@
|
|
|
57
85
|
"type": "git",
|
|
58
86
|
"url": "git+https://github.com/LuanRT/GoogleVideo.git"
|
|
59
87
|
}
|
|
60
|
-
}
|
|
88
|
+
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
|
|
2
|
-
import { HttpHeader } from "../misc/common.js";
|
|
3
|
-
export declare const protobufPackage = "video_streaming";
|
|
4
|
-
export declare enum OnesieProxyStatus {
|
|
5
|
-
ONESIE_PROXY_STATUS_UNKNOWN = 0,
|
|
6
|
-
ONESIE_PROXY_STATUS_OK = 1,
|
|
7
|
-
ONESIE_PROXY_STATUS_DECRYPTION_FAILED = 2,
|
|
8
|
-
ONESIE_PROXY_STATUS_PARSING_FAILED = 3,
|
|
9
|
-
ONESIE_PROXY_STATUS_MISSING_X_FORWARDED_FOR = 4,
|
|
10
|
-
ONESIE_PROXY_STATUS_INVALID_X_FORWARDED_FOR = 5,
|
|
11
|
-
ONESIE_PROXY_STATUS_INVALID_CONTENT_TYPE = 6,
|
|
12
|
-
ONESIE_PROXY_STATUS_BACKEND_ERROR = 7,
|
|
13
|
-
ONESIE_PROXY_STATUS_CLIENT_ERROR = 8,
|
|
14
|
-
ONESIE_PROXY_STATUS_MISSING_CRYPTER = 9,
|
|
15
|
-
ONESIE_PROXY_STATUS_RESPONSE_JSON_SERIALIZATION_FAILED = 10,
|
|
16
|
-
ONESIE_PROXY_STATUS_DECOMPRESSION_FAILED = 11,
|
|
17
|
-
ONESIE_PROXY_STATUS_JSON_PARSING_FAILED = 12,
|
|
18
|
-
ONESIE_PROXY_STATUS_UNKNOWN_COMPRESSION_TYPE = 13,
|
|
19
|
-
UNRECOGNIZED = -1
|
|
20
|
-
}
|
|
21
|
-
export interface OnesiePlayerResponse {
|
|
22
|
-
onesieProxyStatus?: OnesieProxyStatus | undefined;
|
|
23
|
-
httpStatus?: number | undefined;
|
|
24
|
-
headers: HttpHeader[];
|
|
25
|
-
body?: Uint8Array | undefined;
|
|
26
|
-
}
|
|
27
|
-
export declare const OnesiePlayerResponse: MessageFns<OnesiePlayerResponse>;
|
|
28
|
-
export interface MessageFns<T> {
|
|
29
|
-
encode(message: T, writer?: BinaryWriter): BinaryWriter;
|
|
30
|
-
decode(input: BinaryReader | Uint8Array, length?: number): T;
|
|
31
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
|
|
2
|
-
// versions:
|
|
3
|
-
// protoc-gen-ts_proto v2.2.0
|
|
4
|
-
// protoc v3.21.12
|
|
5
|
-
// source: video_streaming/proxy_status.proto
|
|
6
|
-
/* eslint-disable */
|
|
7
|
-
export const protobufPackage = "video_streaming";
|
|
8
|
-
export var ProxyStatus;
|
|
9
|
-
(function (ProxyStatus) {
|
|
10
|
-
ProxyStatus[ProxyStatus["VAL_0"] = 0] = "VAL_0";
|
|
11
|
-
ProxyStatus[ProxyStatus["OK"] = 1] = "OK";
|
|
12
|
-
ProxyStatus[ProxyStatus["VAL_2"] = 2] = "VAL_2";
|
|
13
|
-
ProxyStatus[ProxyStatus["VAL_3"] = 3] = "VAL_3";
|
|
14
|
-
ProxyStatus[ProxyStatus["VAL_4"] = 4] = "VAL_4";
|
|
15
|
-
ProxyStatus[ProxyStatus["VAL_5"] = 5] = "VAL_5";
|
|
16
|
-
ProxyStatus[ProxyStatus["VAL_6"] = 6] = "VAL_6";
|
|
17
|
-
ProxyStatus[ProxyStatus["VAL_7"] = 7] = "VAL_7";
|
|
18
|
-
ProxyStatus[ProxyStatus["VAL_8"] = 8] = "VAL_8";
|
|
19
|
-
ProxyStatus[ProxyStatus["VAL_9"] = 9] = "VAL_9";
|
|
20
|
-
ProxyStatus[ProxyStatus["UNRECOGNIZED"] = -1] = "UNRECOGNIZED";
|
|
21
|
-
})(ProxyStatus || (ProxyStatus = {}));
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { EventEmitterLike } from '../utils/index.js';
|
|
2
|
-
import type { InitOptions, ServerAbrResponse, ServerAbrStreamOptions } from '../utils/types.js';
|
|
3
|
-
export declare class ServerAbrStream extends EventEmitterLike {
|
|
4
|
-
private fetchFunction;
|
|
5
|
-
private serverAbrStreamingUrl;
|
|
6
|
-
private videoPlaybackUstreamerConfig;
|
|
7
|
-
private poToken?;
|
|
8
|
-
private playbackCookie?;
|
|
9
|
-
private totalDurationMs;
|
|
10
|
-
private initializedFormats;
|
|
11
|
-
private formatsByKey;
|
|
12
|
-
private headerIdToFormatKeyMap;
|
|
13
|
-
private previousSequences;
|
|
14
|
-
constructor(args: ServerAbrStreamOptions);
|
|
15
|
-
on(event: 'end', listener: (streamData: ServerAbrResponse) => void): void;
|
|
16
|
-
on(event: 'data', listener: (streamData: ServerAbrResponse) => void): void;
|
|
17
|
-
on(event: 'error', listener: (error: Error) => void): void;
|
|
18
|
-
once(event: 'end', listener: (streamData: ServerAbrResponse) => void): void;
|
|
19
|
-
once(event: 'data', listener: (streamData: ServerAbrResponse) => void): void;
|
|
20
|
-
once(event: 'error', listener: (error: Error) => void): void;
|
|
21
|
-
/**
|
|
22
|
-
* Initializes the server ABR stream with the provided options.
|
|
23
|
-
* @param args - The initialization options.
|
|
24
|
-
*/
|
|
25
|
-
init(args: InitOptions): Promise<void>;
|
|
26
|
-
private fetchMedia;
|
|
27
|
-
/**
|
|
28
|
-
* Parses the UMP response data and updates the initialized formats.
|
|
29
|
-
* @param response - The UMP response data as a byte array.
|
|
30
|
-
*/
|
|
31
|
-
parseUMPResponse(response: Uint8Array): Promise<ServerAbrResponse>;
|
|
32
|
-
private processMediaHeader;
|
|
33
|
-
private processMediaData;
|
|
34
|
-
private processEndOfMedia;
|
|
35
|
-
private processNextRequestPolicy;
|
|
36
|
-
private processFormatInitialization;
|
|
37
|
-
private processSabrRedirect;
|
|
38
|
-
private registerFormat;
|
|
39
|
-
}
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import { UMP } from './UMP.js';
|
|
2
|
-
import { ChunkedDataBuffer } from './ChunkedDataBuffer.js';
|
|
3
|
-
import { EventEmitterLike, PART, QUALITY, base64ToU8, getFormatKey } from '../utils/index.js';
|
|
4
|
-
import { VideoPlaybackAbrRequest } from '../../protos/generated/video_streaming/video_playback_abr_request.js';
|
|
5
|
-
import { MediaHeader } from '../../protos/generated/video_streaming/media_header.js';
|
|
6
|
-
import { NextRequestPolicy } from '../../protos/generated/video_streaming/next_request_policy.js';
|
|
7
|
-
import { FormatInitializationMetadata } from '../../protos/generated/video_streaming/format_initialization_metadata.js';
|
|
8
|
-
import { SabrRedirect } from '../../protos/generated/video_streaming/sabr_redirect.js';
|
|
9
|
-
import { SabrError } from '../../protos/generated/video_streaming/sabr_error.js';
|
|
10
|
-
import { StreamProtectionStatus } from '../../protos/generated/video_streaming/stream_protection_status.js';
|
|
11
|
-
import { PlaybackCookie } from '../../protos/generated/video_streaming/playback_cookie.js';
|
|
12
|
-
const DEFAULT_QUALITY = QUALITY.HD720;
|
|
13
|
-
export class ServerAbrStream extends EventEmitterLike {
|
|
14
|
-
constructor(args) {
|
|
15
|
-
super();
|
|
16
|
-
this.initializedFormats = [];
|
|
17
|
-
this.formatsByKey = new Map();
|
|
18
|
-
this.headerIdToFormatKeyMap = new Map();
|
|
19
|
-
this.previousSequences = new Map();
|
|
20
|
-
this.fetchFunction = args.fetch || fetch;
|
|
21
|
-
this.serverAbrStreamingUrl = args.serverAbrStreamingUrl;
|
|
22
|
-
this.videoPlaybackUstreamerConfig = args.videoPlaybackUstreamerConfig;
|
|
23
|
-
this.poToken = args.poToken;
|
|
24
|
-
this.totalDurationMs = args.durationMs;
|
|
25
|
-
}
|
|
26
|
-
on(event, listener) {
|
|
27
|
-
super.on(event, listener);
|
|
28
|
-
}
|
|
29
|
-
once(event, listener) {
|
|
30
|
-
super.once(event, listener);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Initializes the server ABR stream with the provided options.
|
|
34
|
-
* @param args - The initialization options.
|
|
35
|
-
*/
|
|
36
|
-
async init(args) {
|
|
37
|
-
const { audioFormats, videoFormats, clientAbrState: initialState } = args;
|
|
38
|
-
const firstVideoFormat = videoFormats ? videoFormats[0] : undefined;
|
|
39
|
-
const clientAbrState = {
|
|
40
|
-
lastManualDirection: 0,
|
|
41
|
-
timeSinceLastManualFormatSelectionMs: 0,
|
|
42
|
-
lastManualSelectedResolution: videoFormats.length === 1 ? firstVideoFormat?.height : DEFAULT_QUALITY,
|
|
43
|
-
stickyResolution: videoFormats.length === 1 ? firstVideoFormat?.height : DEFAULT_QUALITY,
|
|
44
|
-
playerTimeMs: 0,
|
|
45
|
-
visibility: 0,
|
|
46
|
-
enabledTrackTypesBitfield: 0,
|
|
47
|
-
...initialState
|
|
48
|
-
};
|
|
49
|
-
const audioFormatIds = audioFormats.map((fmt) => ({
|
|
50
|
-
itag: fmt.itag,
|
|
51
|
-
lastModified: parseInt(fmt.lastModified),
|
|
52
|
-
xtags: fmt.xtags
|
|
53
|
-
}));
|
|
54
|
-
const videoFormatIds = videoFormats.map((fmt) => ({
|
|
55
|
-
itag: fmt.itag,
|
|
56
|
-
lastModified: parseInt(fmt.lastModified),
|
|
57
|
-
xtags: fmt.xtags
|
|
58
|
-
}));
|
|
59
|
-
if (typeof clientAbrState.playerTimeMs !== 'number')
|
|
60
|
-
throw new Error('Invalid media start time');
|
|
61
|
-
try {
|
|
62
|
-
while (clientAbrState.playerTimeMs < this.totalDurationMs) {
|
|
63
|
-
const data = await this.fetchMedia({ clientAbrState, audioFormatIds, videoFormatIds });
|
|
64
|
-
this.emit('data', data);
|
|
65
|
-
if (data.sabrError)
|
|
66
|
-
break;
|
|
67
|
-
const mainFormat = clientAbrState.enabledTrackTypesBitfield === 0
|
|
68
|
-
? data.initializedFormats.find((fmt) => fmt.mimeType?.includes('video'))
|
|
69
|
-
: data.initializedFormats[0];
|
|
70
|
-
for (const fmt of data.initializedFormats) {
|
|
71
|
-
this.previousSequences.set(fmt.formatKey, fmt.sequenceList.map((seq) => seq.sequenceNumber || 0));
|
|
72
|
-
}
|
|
73
|
-
if (!mainFormat ||
|
|
74
|
-
mainFormat.sequenceCount ===
|
|
75
|
-
mainFormat.sequenceList[mainFormat.sequenceList.length - 1]?.sequenceNumber) {
|
|
76
|
-
this.emit('end', data);
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
clientAbrState.playerTimeMs += mainFormat.sequenceList.reduce((acc, seq) => acc + (seq.durationMs || 0), 0);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
this.emit('error', error);
|
|
84
|
-
clientAbrState.playerTimeMs = Infinity;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
async fetchMedia(args) {
|
|
88
|
-
const { clientAbrState, audioFormatIds, videoFormatIds } = args;
|
|
89
|
-
const body = VideoPlaybackAbrRequest.encode({
|
|
90
|
-
clientAbrState: clientAbrState,
|
|
91
|
-
selectedAudioFormatIds: audioFormatIds,
|
|
92
|
-
selectedVideoFormatIds: videoFormatIds,
|
|
93
|
-
selectedFormatIds: this.initializedFormats.map((fmt) => fmt.formatId),
|
|
94
|
-
videoPlaybackUstreamerConfig: base64ToU8(this.videoPlaybackUstreamerConfig),
|
|
95
|
-
streamerContext: {
|
|
96
|
-
field5: [],
|
|
97
|
-
field6: [],
|
|
98
|
-
poToken: this.poToken ? base64ToU8(this.poToken) : undefined,
|
|
99
|
-
playbackCookie: this.playbackCookie ? PlaybackCookie.encode(this.playbackCookie).finish() : undefined,
|
|
100
|
-
clientInfo: {
|
|
101
|
-
clientName: 1,
|
|
102
|
-
clientVersion: '2.2040620.05.00',
|
|
103
|
-
osName: 'Windows',
|
|
104
|
-
osVersion: '10.0'
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
bufferedRanges: this.initializedFormats.map((fmt) => fmt._state),
|
|
108
|
-
field1000: []
|
|
109
|
-
}).finish();
|
|
110
|
-
const response = await this.fetchFunction(this.serverAbrStreamingUrl, { method: 'POST', body });
|
|
111
|
-
const data = await response.arrayBuffer();
|
|
112
|
-
if (response.status !== 200 || !data.byteLength)
|
|
113
|
-
throw new Error(`Received an invalid response from the server: ${response.status}`);
|
|
114
|
-
return this.parseUMPResponse(new Uint8Array(data));
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Parses the UMP response data and updates the initialized formats.
|
|
118
|
-
* @param response - The UMP response data as a byte array.
|
|
119
|
-
*/
|
|
120
|
-
async parseUMPResponse(response) {
|
|
121
|
-
this.headerIdToFormatKeyMap.clear();
|
|
122
|
-
this.initializedFormats.forEach((format) => {
|
|
123
|
-
format.sequenceList = [];
|
|
124
|
-
format.mediaChunks = [];
|
|
125
|
-
});
|
|
126
|
-
let sabrError;
|
|
127
|
-
let sabrRedirect;
|
|
128
|
-
let streamProtectionStatus;
|
|
129
|
-
const ump = new UMP(new ChunkedDataBuffer([response]));
|
|
130
|
-
ump.parse((part) => {
|
|
131
|
-
const data = part.data.chunks[0];
|
|
132
|
-
switch (part.type) {
|
|
133
|
-
case PART.MEDIA_HEADER:
|
|
134
|
-
this.processMediaHeader(data);
|
|
135
|
-
break;
|
|
136
|
-
case PART.MEDIA:
|
|
137
|
-
this.processMediaData(part.data);
|
|
138
|
-
break;
|
|
139
|
-
case PART.MEDIA_END:
|
|
140
|
-
this.processEndOfMedia(part.data);
|
|
141
|
-
break;
|
|
142
|
-
case PART.NEXT_REQUEST_POLICY:
|
|
143
|
-
this.processNextRequestPolicy(data);
|
|
144
|
-
break;
|
|
145
|
-
case PART.FORMAT_INITIALIZATION_METADATA:
|
|
146
|
-
this.processFormatInitialization(data);
|
|
147
|
-
break;
|
|
148
|
-
case PART.SABR_ERROR:
|
|
149
|
-
sabrError = SabrError.decode(data);
|
|
150
|
-
break;
|
|
151
|
-
case PART.SABR_REDIRECT:
|
|
152
|
-
sabrRedirect = this.processSabrRedirect(data);
|
|
153
|
-
break;
|
|
154
|
-
case PART.STREAM_PROTECTION_STATUS:
|
|
155
|
-
streamProtectionStatus = StreamProtectionStatus.decode(data);
|
|
156
|
-
break;
|
|
157
|
-
default:
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
return {
|
|
162
|
-
initializedFormats: this.initializedFormats,
|
|
163
|
-
streamProtectionStatus,
|
|
164
|
-
sabrRedirect,
|
|
165
|
-
sabrError
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
processMediaHeader(data) {
|
|
169
|
-
const mediaHeader = MediaHeader.decode(data);
|
|
170
|
-
if (!mediaHeader.formatId)
|
|
171
|
-
return;
|
|
172
|
-
const formatKey = getFormatKey(mediaHeader.formatId);
|
|
173
|
-
const currentFormat = this.formatsByKey.get(formatKey) || this.registerFormat(mediaHeader);
|
|
174
|
-
if (!currentFormat)
|
|
175
|
-
return;
|
|
176
|
-
// FIXME: This is a hacky workaround to prevent duplicate sequences from being added. This should be fixed in the future (preferably by figuring out how to make the server not send duplicates).
|
|
177
|
-
if (mediaHeader.sequenceNumber !== undefined && this.previousSequences.get(formatKey)?.includes(mediaHeader.sequenceNumber))
|
|
178
|
-
return;
|
|
179
|
-
// Save the header's ID so we can identify its stream data later.
|
|
180
|
-
if (mediaHeader.headerId !== undefined) {
|
|
181
|
-
if (!this.headerIdToFormatKeyMap.has(mediaHeader.headerId)) {
|
|
182
|
-
this.headerIdToFormatKeyMap.set(mediaHeader.headerId, formatKey);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
if (!currentFormat.sequenceList.some((seq) => seq.sequenceNumber === (mediaHeader.sequenceNumber || 0))) {
|
|
186
|
-
currentFormat.sequenceList.push({
|
|
187
|
-
itag: mediaHeader.itag,
|
|
188
|
-
formatId: mediaHeader.formatId,
|
|
189
|
-
isInitSegment: mediaHeader.isInitSeg,
|
|
190
|
-
durationMs: mediaHeader.durationMs,
|
|
191
|
-
startMs: mediaHeader.startMs,
|
|
192
|
-
startDataRange: mediaHeader.startDataRange,
|
|
193
|
-
sequenceNumber: mediaHeader.sequenceNumber,
|
|
194
|
-
contentLength: mediaHeader.contentLength,
|
|
195
|
-
timeRange: mediaHeader.timeRange
|
|
196
|
-
});
|
|
197
|
-
if (typeof mediaHeader.sequenceNumber === 'number') {
|
|
198
|
-
currentFormat._state.durationMs += mediaHeader.durationMs || 0;
|
|
199
|
-
currentFormat._state.endSegmentIndex += 1;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
processMediaData(data) {
|
|
204
|
-
const headerId = data.getUint8(0);
|
|
205
|
-
const streamData = data.split(1).remainingBuffer;
|
|
206
|
-
const formatKey = this.headerIdToFormatKeyMap.get(headerId);
|
|
207
|
-
if (!formatKey)
|
|
208
|
-
return;
|
|
209
|
-
const currentFormat = this.formatsByKey.get(formatKey);
|
|
210
|
-
if (!currentFormat)
|
|
211
|
-
return;
|
|
212
|
-
currentFormat.mediaChunks.push(streamData.chunks[0]);
|
|
213
|
-
}
|
|
214
|
-
processEndOfMedia(data) {
|
|
215
|
-
const headerId = data.getUint8(0);
|
|
216
|
-
this.headerIdToFormatKeyMap.delete(headerId);
|
|
217
|
-
}
|
|
218
|
-
processNextRequestPolicy(data) {
|
|
219
|
-
const nextRequestPolicy = NextRequestPolicy.decode(data);
|
|
220
|
-
this.playbackCookie = nextRequestPolicy.playbackCookie;
|
|
221
|
-
}
|
|
222
|
-
processFormatInitialization(data) {
|
|
223
|
-
const formatInitializationMetadata = FormatInitializationMetadata.decode(data);
|
|
224
|
-
this.registerFormat(formatInitializationMetadata);
|
|
225
|
-
}
|
|
226
|
-
processSabrRedirect(data) {
|
|
227
|
-
const sabrRedirect = SabrRedirect.decode(data);
|
|
228
|
-
if (!sabrRedirect.url)
|
|
229
|
-
throw new Error('Invalid SABR redirect');
|
|
230
|
-
this.serverAbrStreamingUrl = sabrRedirect.url;
|
|
231
|
-
return sabrRedirect;
|
|
232
|
-
}
|
|
233
|
-
registerFormat(data) {
|
|
234
|
-
if (!data.formatId)
|
|
235
|
-
return;
|
|
236
|
-
const formatKey = getFormatKey(data.formatId);
|
|
237
|
-
if (!this.formatsByKey.has(formatKey)) {
|
|
238
|
-
const format = {
|
|
239
|
-
formatId: data.formatId,
|
|
240
|
-
formatKey: formatKey,
|
|
241
|
-
durationMs: data.durationMs,
|
|
242
|
-
mimeType: 'mimeType' in data ? data.mimeType : undefined,
|
|
243
|
-
sequenceCount: 'field4' in data ? data.field4 : undefined,
|
|
244
|
-
sequenceList: [],
|
|
245
|
-
mediaChunks: [],
|
|
246
|
-
_state: {
|
|
247
|
-
formatId: data.formatId,
|
|
248
|
-
startTimeMs: 0,
|
|
249
|
-
durationMs: 0,
|
|
250
|
-
startSegmentIndex: 1,
|
|
251
|
-
endSegmentIndex: 0
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
this.initializedFormats.push(format);
|
|
255
|
-
this.formatsByKey.set(formatKey, this.initializedFormats[this.initializedFormats.length - 1]);
|
|
256
|
-
return format;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
package/dist/src/core/index.d.ts
DELETED
package/dist/src/core/index.js
DELETED
package/dist/src/index.d.ts
DELETED
package/dist/src/index.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type { FormatId } from '../../protos/generated/misc/common.js';
|
|
2
|
-
export declare enum QUALITY {
|
|
3
|
-
AUTO = 0,
|
|
4
|
-
TINY = 144,
|
|
5
|
-
SMALL = 240,
|
|
6
|
-
MEDIUM = 360,
|
|
7
|
-
LIGHT = 144,
|
|
8
|
-
LARGE = 480,
|
|
9
|
-
HD720 = 720,
|
|
10
|
-
HD1080 = 1080,
|
|
11
|
-
HD1440 = 1440,
|
|
12
|
-
HD2160 = 2160,
|
|
13
|
-
HD2880 = 2880,
|
|
14
|
-
HIGHRES = 4320
|
|
15
|
-
}
|
|
16
|
-
export declare enum PART {
|
|
17
|
-
ONESIE_HEADER = 10,
|
|
18
|
-
ONESIE_DATA = 11,
|
|
19
|
-
MEDIA_HEADER = 20,
|
|
20
|
-
MEDIA = 21,
|
|
21
|
-
MEDIA_END = 22,
|
|
22
|
-
LIVE_METADATA = 31,
|
|
23
|
-
HOSTNAME_CHANGE_HINT = 32,
|
|
24
|
-
LIVE_METADATA_PROMISE = 33,
|
|
25
|
-
LIVE_METADATA_PROMISE_CANCELLATION = 34,
|
|
26
|
-
NEXT_REQUEST_POLICY = 35,
|
|
27
|
-
USTREAMER_VIDEO_AND_FORMAT_DATA = 36,
|
|
28
|
-
FORMAT_SELECTION_CONFIG = 37,
|
|
29
|
-
USTREAMER_SELECTED_MEDIA_STREAM = 38,
|
|
30
|
-
FORMAT_INITIALIZATION_METADATA = 42,
|
|
31
|
-
SABR_REDIRECT = 43,
|
|
32
|
-
SABR_ERROR = 44,
|
|
33
|
-
SABR_SEEK = 45,
|
|
34
|
-
RELOAD_PLAYER_RESPONSE = 46,
|
|
35
|
-
PLAYBACK_START_POLICY = 47,
|
|
36
|
-
ALLOWED_CACHED_FORMATS = 48,
|
|
37
|
-
START_BW_SAMPLING_HINT = 49,
|
|
38
|
-
PAUSE_BW_SAMPLING_HINT = 50,
|
|
39
|
-
SELECTABLE_FORMATS = 51,
|
|
40
|
-
REQUEST_IDENTIFIER = 52,
|
|
41
|
-
REQUEST_CANCELLATION_POLICY = 53,
|
|
42
|
-
ONESIE_PREFETCH_REJECTION = 54,
|
|
43
|
-
TIMELINE_CONTEXT = 55,
|
|
44
|
-
REQUEST_PIPELINING = 56,
|
|
45
|
-
SABR_CONTEXT_UPDATE = 57,
|
|
46
|
-
STREAM_PROTECTION_STATUS = 58,
|
|
47
|
-
SABR_CONTEXT_SENDING_POLICY = 59,
|
|
48
|
-
LAWNMOWER_POLICY = 60,
|
|
49
|
-
SABR_ACK = 61,
|
|
50
|
-
END_OF_TRACK = 62,
|
|
51
|
-
CACHE_LOAD_POLICY = 63,
|
|
52
|
-
LAWNMOWER_MESSAGING_POLICY = 64,
|
|
53
|
-
PREWARM_CONNECTION = 65
|
|
54
|
-
}
|
|
55
|
-
export declare function u8ToBase64(u8: Uint8Array): string;
|
|
56
|
-
export declare function base64ToU8(base64: string): Uint8Array;
|
|
57
|
-
export declare function getFormatKey(formatId: FormatId): string;
|
|
58
|
-
export declare function concatenateChunks(chunks: Uint8Array[]): Uint8Array;
|
|
59
|
-
export declare class CustomEvent extends Event {
|
|
60
|
-
#private;
|
|
61
|
-
constructor(type: string, options?: CustomEventInit<any[]>);
|
|
62
|
-
get detail(): any[] | null;
|
|
63
|
-
}
|