Skip to content

Commit c95d81a

Browse files
improve: reduce sabr allocations & potoken bugfixes
1 parent b6572bf commit c95d81a

3 files changed

Lines changed: 143 additions & 62 deletions

File tree

src/sources/youtube/potoke.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,21 @@ export class PoTokenManager {
239239
};
240240
}
241241

242-
async initialize() {
242+
async initialize(existingVisitorData) {
243+
if (existingVisitorData && this.visitorData && existingVisitorData !== this.visitorData) {
244+
logger('debug', 'PoToken', `VisitorData changed (old: ${this.visitorData.slice(0, 10)}..., new: ${existingVisitorData.slice(0, 10)}...). Resetting.`);
245+
this.reset();
246+
}
247+
243248
if (this.botguard && this.minter) return;
244249

245250
logger('debug', 'PoToken', 'Initializing BotGuard...');
246251

247-
this.visitorData = await this.fetchVisitorData();
252+
if (existingVisitorData) {
253+
this.visitorData = existingVisitorData;
254+
} else {
255+
this.visitorData = await this.fetchVisitorData();
256+
}
248257
logger('debug', 'PoToken', `VisitorData: ${this.visitorData?.slice(0, 20)}...`);
249258

250259
this._cleanupDom();
@@ -302,11 +311,11 @@ export class PoTokenManager {
302311
logger('debug', 'PoToken', 'Initialization complete');
303312
}
304313

305-
async generate(videoId) {
314+
async generate(videoId, existingVisitorData) {
306315
try {
307-
logger('debug', 'PoToken', `Generating token for videoId: ${videoId}`);
316+
logger('debug', 'PoToken', `Generating token for videoId: ${videoId} with existingVisitorData: ${!!existingVisitorData}`);
308317

309-
await this.initialize();
318+
await this.initialize(existingVisitorData);
310319

311320
const contentPoToken = await this.minter.mintAsWebsafeString(videoId);
312321
logger('debug', 'PoToken', `ContentPoToken generated. Length: ${contentPoToken.length}`);

src/sources/youtube/protor.js

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
1-
import { Buffer } from 'node:buffer'
1+
import { Buffer } from 'node:buffer';
2+
3+
const TD = new TextDecoder();
4+
const EMPTY_U8 = new Uint8Array(0);
25

36
export class ProtoWriter {
4-
constructor() { this.chunks = []; }
7+
constructor() { this.chunks = []; this.length = 0; }
8+
_push(c) {
9+
this.chunks.push(c);
10+
this.length += typeof c === 'number' ? 1 : c.length;
11+
}
512
writeVarint(value) {
613
let v = BigInt(value);
7-
while (v > 127n) { this.chunks.push((Number(v & 127n) | 128)); v >>= 7n; }
8-
this.chunks.push(Number(v));
14+
while (v > 127n) { this._push((Number(v & 127n) | 128)); v >>= 7n; }
15+
this._push(Number(v));
916
}
1017
writeTag(fieldNumber, wireType) { this.writeVarint((fieldNumber << 3) | wireType); }
1118
writeString(fieldNumber, str) {
1219
if (!str) return; // Canonical: omit "", null, undefined
1320
const buf = Buffer.from(str, 'utf8');
1421
this.writeTag(fieldNumber, 2);
1522
this.writeVarint(buf.length);
16-
this.chunks.push(buf);
23+
this._push(buf);
1724
}
1825
writeBytes(fieldNumber, buffer) {
1926
if (!buffer || buffer.length === 0) return; // Canonical: omit
@@ -22,7 +29,7 @@ export class ProtoWriter {
2229
}
2330
this.writeTag(fieldNumber, 2);
2431
this.writeVarint(buffer.length);
25-
this.chunks.push(buffer);
32+
this._push(buffer);
2633
}
2734
writeInt32(fieldNumber, value) {
2835
if (!value) return; // Canonical: omit 0, null, undefined
@@ -45,18 +52,17 @@ export class ProtoWriter {
4552
this.writeTag(fieldNumber, 5);
4653
const buf = Buffer.alloc(4);
4754
buf.writeFloatLE(value);
48-
this.chunks.push(buf);
55+
this._push(buf);
4956
}
5057
writeMessage(fieldNumber, writer) {
5158
const buf = writer.finish();
5259
if (buf.length === 0) return;
5360
this.writeTag(fieldNumber, 2);
5461
this.writeVarint(buf.length);
55-
this.chunks.push(buf);
62+
this._push(buf);
5663
}
5764
finish() {
58-
const totalLen = this.chunks.reduce((acc, c) => acc + (typeof c === 'number' ? 1 : c.length), 0);
59-
const buf = new Uint8Array(totalLen);
65+
const buf = new Uint8Array(this.length);
6066
let offset = 0;
6167
for (const c of this.chunks) {
6268
if (typeof c === 'number') buf[offset++] = c;
@@ -80,16 +86,15 @@ export class ProtoReader {
8086
return result;
8187
}
8288
readString() {
83-
const v = this.readVarint();
84-
const len = Number(v);
89+
const len = Number(this.readVarint());
8590
if (this.pos + len > this.buffer.length) return "";
86-
const str = new TextDecoder().decode(this.buffer.subarray(this.pos, this.pos + len));
91+
const str = TD.decode(this.buffer.subarray(this.pos, this.pos + len));
8792
this.pos += len;
8893
return str;
8994
}
9095
readBytes() {
9196
const len = Number(this.readVarint());
92-
if (this.pos + len > this.buffer.length) return new Uint8Array(0);
97+
if (this.pos + len > this.buffer.length) return EMPTY_U8;
9398
const bytes = this.buffer.subarray(this.pos, this.pos + len);
9499
this.pos += len;
95100
return bytes;
@@ -393,7 +398,7 @@ export const NextRequestPolicy = {
393398
function isMostlyPrintableUtf8(u8) {
394399
if (!u8 || !u8.length) return false;
395400
try {
396-
const s = new TextDecoder().decode(u8);
401+
const s = TD.decode(u8);
397402
if (!s) return false;
398403
let ok = 0;
399404
for (let i = 0; i < s.length; i++) {
@@ -430,7 +435,7 @@ function decodeProtobufObject(reader, len, depth = 2) {
430435
} else if (wireType === 2) {
431436
const b = reader.readBytes();
432437
const entry = { len: b.length };
433-
if (isMostlyPrintableUtf8(b) && b.length <= 256) entry.utf8 = new TextDecoder().decode(b);
438+
if (isMostlyPrintableUtf8(b) && b.length <= 256) entry.utf8 = TD.decode(b);
434439
if (depth > 0 && b.length) {
435440
try {
436441
const nested = decodeProtobufObject(new ProtoReader(b), b.length, depth - 1);
@@ -475,6 +480,13 @@ export const RequestCancellationPolicy = {
475480
}
476481
};
477482

483+
export const ReloadPlaybackContext = {
484+
decode(reader, len) {
485+
// Unknown schema; return wire-level decoded object like other unknown messages.
486+
return decodeProtobufObject(reader, len, 2);
487+
}
488+
};
489+
478490
export const StreamerContext = {
479491
encode(msg, writer) {
480492
if (msg.clientInfo) {
@@ -526,9 +538,12 @@ export const UMPPartId = {
526538
};
527539

528540
export function base64ToU8(base64) {
529-
const standard_base64 = base64.replace(/-/g, '+').replace(/_/g, '/');
530-
const padded_base64 = standard_base64.padEnd(standard_base64.length + (4 - standard_base64.length % 4) % 4, '=');
531-
return new Uint8Array(Buffer.from(padded_base64, 'base64'));
541+
let s = base64;
542+
if (s.includes('-')) s = s.replaceAll('-', '+');
543+
if (s.includes('_')) s = s.replaceAll('_', '/');
544+
const mod = s.length & 3;
545+
if (mod) s += '='.repeat(4 - mod);
546+
return new Uint8Array(Buffer.from(s, 'base64'));
532547
}
533548

534549
export function concatenateChunks(chunks) {

0 commit comments

Comments
 (0)