mirror of
https://github.com/anidl/multi-downloader-nx.git
synced 2026-03-11 17:45:30 +00:00
fixed playready wrm header extraction from pssh
This commit is contained in:
parent
1a192d2192
commit
bed0b6a918
1 changed files with 27 additions and 65 deletions
|
|
@ -14,54 +14,11 @@ const PSSHBox = new Parser()
|
||||||
length: 'data_length'
|
length: 'data_length'
|
||||||
});
|
});
|
||||||
|
|
||||||
const PlayreadyObject = new Parser()
|
export function isPlayreadyPsshBox(data: Buffer): boolean {
|
||||||
.useContextVars()
|
|
||||||
.uint16('type')
|
|
||||||
.uint16('length')
|
|
||||||
.choice('data', {
|
|
||||||
tag: 'type',
|
|
||||||
choices: {
|
|
||||||
1: new Parser().string('data', {
|
|
||||||
length: function () {
|
|
||||||
return (this as any).$parent.length;
|
|
||||||
},
|
|
||||||
encoding: 'utf16le'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
defaultChoice: new Parser().buffer('data', {
|
|
||||||
length: function () {
|
|
||||||
return (this as any).$parent.length;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
const PlayreadyHeader = new Parser().uint32('length').uint16('record_count').array('records', {
|
|
||||||
length: 'record_count',
|
|
||||||
type: PlayreadyObject
|
|
||||||
});
|
|
||||||
|
|
||||||
function isPlayreadyPsshBox(data: Buffer): boolean {
|
|
||||||
if (data.length < 28) return false;
|
if (data.length < 28) return false;
|
||||||
return data.subarray(12, 28).equals(SYSTEM_ID);
|
return data.subarray(12, 28).equals(SYSTEM_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isUtf16(data: Buffer): boolean {
|
|
||||||
for (let i = 1; i < data.length; i += 2) {
|
|
||||||
if (data[i] !== 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function* getWrmHeaders(wrm_header: any): IterableIterator<string> {
|
|
||||||
for (const record of wrm_header.records) {
|
|
||||||
if (record.type === 1 && typeof record.data === 'string') {
|
|
||||||
yield record.data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PSSH {
|
export class PSSH {
|
||||||
public wrm_headers: string[];
|
public wrm_headers: string[];
|
||||||
|
|
||||||
|
|
@ -80,37 +37,42 @@ export class PSSH {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isPlayreadyPsshBox(data)) {
|
if (isPlayreadyPsshBox(data)) {
|
||||||
const pssh_box = PSSHBox.parse(data);
|
const header = this.extractPlayreadyHeader(data);
|
||||||
const psshData = pssh_box.data;
|
if (header) {
|
||||||
|
this.wrm_headers = [header];
|
||||||
if (isUtf16(psshData)) {
|
|
||||||
this.wrm_headers = [psshData.toString('utf16le')];
|
|
||||||
} else if (isUtf16(psshData.subarray(6))) {
|
|
||||||
this.wrm_headers = [psshData.subarray(6).toString('utf16le')];
|
|
||||||
} else if (isUtf16(psshData.subarray(10))) {
|
|
||||||
this.wrm_headers = [psshData.subarray(10).toString('utf16le')];
|
|
||||||
} else {
|
} else {
|
||||||
const playready_header = PlayreadyHeader.parse(psshData);
|
throw new Error('Invalid PlayReady Header');
|
||||||
this.wrm_headers = Array.from(getWrmHeaders(playready_header));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isUtf16(data)) {
|
const repairedHeader = this.extractPlayreadyHeader(data);
|
||||||
this.wrm_headers = [data.toString('utf16le')];
|
if (repairedHeader) {
|
||||||
} else if (isUtf16(data.subarray(6))) {
|
this.wrm_headers = [repairedHeader];
|
||||||
this.wrm_headers = [data.subarray(6).toString('utf16le')];
|
|
||||||
} else if (isUtf16(data.subarray(10))) {
|
|
||||||
this.wrm_headers = [data.subarray(10).toString('utf16le')];
|
|
||||||
} else {
|
} else {
|
||||||
const playready_header = PlayreadyHeader.parse(data);
|
throw new Error('Could not extract PlayReady header from repaired data');
|
||||||
this.wrm_headers = Array.from(getWrmHeaders(playready_header));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error('Could not parse data as a PSSH Box nor a PlayReadyHeader');
|
throw new Error(`Could not parse or repair PSSH data: ${e}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extractPlayreadyHeader(data: Buffer): string | null {
|
||||||
|
try {
|
||||||
|
const utf16Data = data.toString('utf16le');
|
||||||
|
|
||||||
|
const wrmHeaderMatch = utf16Data.match(/<WRMHEADER[^>]*>.*<\/WRMHEADER>/i);
|
||||||
|
if (wrmHeaderMatch && wrmHeaderMatch.length > 0) {
|
||||||
|
return wrmHeaderMatch[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn('No valid WRMHEADER found in PSSH data');
|
||||||
|
return null;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to extract PlayReady header:', e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header downgrade
|
|
||||||
public get_wrm_headers(downgrade_to_v4: boolean = false): string[] {
|
public get_wrm_headers(downgrade_to_v4: boolean = false): string[] {
|
||||||
return this.wrm_headers.map(downgrade_to_v4 ? this.downgradePSSH : (_) => _);
|
return this.wrm_headers.map(downgrade_to_v4 ? this.downgradePSSH : (_) => _);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue