added better decryption error handeling and updated endpoint
This commit is contained in:
parent
448c206101
commit
7640c2ea89
@ -710,11 +710,38 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
if (playlist.mediaGroups.AUDIO.audio.main.playlists[0].contentProtection) {
|
if (playlist.mediaGroups.AUDIO.audio.main.playlists[0].contentProtection) {
|
||||||
if (!playlist.mediaGroups.AUDIO.audio.main.playlists[0].contentProtection['com.widevine.alpha'].pssh) {
|
if (!playlist.mediaGroups.AUDIO.audio.main.playlists[0].contentProtection['com.widevine.alpha'].pssh) {
|
||||||
console.log('No PSSH found, exiting.')
|
console.log('No PSSH found, exiting.')
|
||||||
|
messageBox(
|
||||||
|
'error',
|
||||||
|
['Cancel'],
|
||||||
|
2,
|
||||||
|
'Encryption Detect error',
|
||||||
|
'Encryption Detect error',
|
||||||
|
'Audio file is decrypted, but it looks like not with widevine. Stopping Download. Contact Developer'
|
||||||
|
)
|
||||||
|
server.logger.log({
|
||||||
|
level: 'error',
|
||||||
|
message: `Audio file is decrypted, but it looks like not with widevine in Download ${downloadID}`,
|
||||||
|
error: 'No PSSH found',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
section: 'crunchyrollDownloadProcessAudioDecryption'
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pssh = Uint8ArrayToBase64(playlist.mediaGroups.AUDIO.audio.main.playlists[0].contentProtection['com.widevine.alpha'].pssh)
|
pssh = Uint8ArrayToBase64(playlist.mediaGroups.AUDIO.audio.main.playlists[0].contentProtection['com.widevine.alpha'].pssh)
|
||||||
|
|
||||||
keys = await getDRMKeys(pssh, assetId[1], list.account_id)
|
keys = await getDRMKeys(pssh, assetId[1], list.account_id)
|
||||||
|
|
||||||
|
if (!keys) {
|
||||||
|
await updatePlaylistByID(downloadID, 'failed')
|
||||||
|
server.logger.log({
|
||||||
|
level: 'error',
|
||||||
|
message: `No decryption keys, failing Download ${downloadID}`,
|
||||||
|
error: 'No decryption keys',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
section: 'crunchyrollDownloadProcessAudioDecryption'
|
||||||
|
})
|
||||||
|
throw Error(`No decryption keys, failing Download ${downloadID}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -925,6 +952,18 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
pssh = Uint8ArrayToBase64(hq.contentProtection['com.widevine.alpha'].pssh)
|
pssh = Uint8ArrayToBase64(hq.contentProtection['com.widevine.alpha'].pssh)
|
||||||
|
|
||||||
keys = await getDRMKeys(pssh, assetId[1], play.account_id)
|
keys = await getDRMKeys(pssh, assetId[1], play.account_id)
|
||||||
|
|
||||||
|
if (!keys) {
|
||||||
|
await updatePlaylistByID(downloadID, 'failed')
|
||||||
|
server.logger.log({
|
||||||
|
level: 'error',
|
||||||
|
message: `No decryption keys, failing Download ${downloadID}`,
|
||||||
|
error: 'No decryption keys',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
section: 'crunchyrollDownloadProcessVideoDecryption'
|
||||||
|
})
|
||||||
|
throw Error(`No decryption keys, failing Download ${downloadID}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((hq.contentProtection && !drmL3blob && !drmL3key) || (hq.contentProtection && !drmL3blob) || (hq.contentProtection && !drmL3key)) {
|
if ((hq.contentProtection && !drmL3blob && !drmL3key) || (hq.contentProtection && !drmL3blob) || (hq.contentProtection && !drmL3key)) {
|
||||||
|
@ -1,9 +1,22 @@
|
|||||||
import { Session } from '../modules/license'
|
import { Session } from '../modules/license'
|
||||||
import { readFileSync } from 'fs'
|
import { readFileSync } from 'fs'
|
||||||
import { getWVKPath } from './widevine'
|
import { getWVKPath } from './widevine'
|
||||||
|
import { messageBox } from '../../electron/background'
|
||||||
|
import { server } from '../api'
|
||||||
|
|
||||||
export async function getDRMKeys(pssh: string, assetID: string, userID: string) {
|
export async function getDRMKeys(pssh: string, assetID: string, userID: string) {
|
||||||
const auth = await getWVKey(assetID, userID)
|
const auth = await getWVKey(assetID, userID)
|
||||||
|
|
||||||
|
if (!auth) {
|
||||||
|
server.logger.log({
|
||||||
|
level: 'error',
|
||||||
|
message: 'WVKey missing, aborting',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
section: 'drmAuthCrunchyrollStatus'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const depssh = Buffer.from(pssh, 'base64')
|
const depssh = Buffer.from(pssh, 'base64')
|
||||||
|
|
||||||
const keys = await getWVKPath()
|
const keys = await getWVKPath()
|
||||||
@ -14,23 +27,36 @@ export async function getDRMKeys(pssh: string, assetID: string, userID: string)
|
|||||||
|
|
||||||
if (!keys.client) return
|
if (!keys.client) return
|
||||||
|
|
||||||
const privateKey = readFileSync(keys.key)
|
try {
|
||||||
const identifierBlob = readFileSync(keys.client)
|
const privateKey = readFileSync(keys.key)
|
||||||
|
const identifierBlob = readFileSync(keys.client)
|
||||||
|
|
||||||
const session = new Session({ privateKey, identifierBlob }, depssh)
|
const session = new Session({ privateKey, identifierBlob }, depssh)
|
||||||
|
|
||||||
const response = await fetch('https://lic.drmtoday.com/license-proxy-widevine/cenc/', {
|
const response = await fetch('https://lic.drmtoday.com/license-proxy-widevine/cenc/', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: session.createLicenseRequest(),
|
body: session.createLicenseRequest(),
|
||||||
headers: {
|
headers: {
|
||||||
'dt-custom-data': auth.custom_data,
|
'dt-custom-data': auth.custom_data,
|
||||||
'x-dt-auth-token': auth.token
|
'x-dt-auth-token': auth.token
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const json = JSON.parse(await response.text())
|
||||||
|
return session.parseLicense(Buffer.from(json['license'], 'base64')) as { kid: string; key: string }[]
|
||||||
|
} else {
|
||||||
|
throw Error(await response.text())
|
||||||
}
|
}
|
||||||
})
|
} catch (e) {
|
||||||
|
messageBox('error', ['Cancel'], 2, 'Error while getting video/audio decryption keys', 'Error while getting video/audio decryption keys', String(e))
|
||||||
if (response.ok) {
|
server.logger.log({
|
||||||
const json = JSON.parse(await response.text())
|
level: 'error',
|
||||||
return session.parseLicense(Buffer.from(json['license'], 'base64')) as { kid: string; key: string }[]
|
message: 'Error while getting video/audio decryption keys',
|
||||||
|
error: String(e),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
section: 'drmVideoAudioKeyCrunchyrollFetch'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +69,7 @@ export async function getWVKey(assetID: string, userID: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`https://pl.crunchyroll.com/drm/v1/auth`, {
|
const response = await fetch(`https://beta-api.crunchyroll.com/drm/v1/auth`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(body)
|
body: JSON.stringify(body)
|
||||||
})
|
})
|
||||||
@ -59,7 +85,14 @@ export async function getWVKey(assetID: string, userID: string) {
|
|||||||
throw new Error(await response.text())
|
throw new Error(await response.text())
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(e as string)
|
messageBox('error', ['Cancel'], 2, 'Failed to Fetch Decryption token', 'Failed to Fetch Decryption token', String(e))
|
||||||
|
server.logger.log({
|
||||||
|
level: 'error',
|
||||||
|
message: 'Failed to Fetch Decryption token',
|
||||||
|
error: String(e),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
section: 'drmAuthCrunchyrollFetch'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user