added video token deletion after mpd fetch
This commit is contained in:
parent
200f757a18
commit
bd7117d030
@ -10,11 +10,12 @@
|
||||
<div class="text-[11px] text-white font-dm"> ADD DOWNLOAD </div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="w-full flex flex-row items-center justify-center">
|
||||
<div class="relative w-full flex flex-row items-center justify-center">
|
||||
<img src="/logo.png" class="h-8" />
|
||||
<div class="text-[10px] leading-[10px] text-opacity-90 text-white select-none"
|
||||
>Crunchyroll <br />
|
||||
Downloader</div
|
||||
Downloader <br />
|
||||
Advanced</div
|
||||
>
|
||||
</div>
|
||||
<div class="w-full flex gap-2 flex-row items-center justify-center">
|
||||
|
@ -37,6 +37,10 @@
|
||||
<Icon name="mdi:loading" class="h-3.5 w-3.5 text-white animate-spin" />
|
||||
{{ p.status }}
|
||||
</div>
|
||||
<div v-if="p.status === 'decrypting'" class="flex flex-row items-center justify-center gap-1 text-xs capitalize p-1.5 bg-[#866332] rounded-lg">
|
||||
<Icon name="mdi:loading" class="h-3.5 w-3.5 text-white animate-spin" />
|
||||
{{ p.status }}
|
||||
</div>
|
||||
<div v-if="p.status === 'completed'" class="flex flex-row items-center justify-center gap-1 text-xs capitalize p-1.5 bg-[#266326] rounded-lg">
|
||||
<Icon name="material-symbols:check" class="h-3.5 w-3.5 text-white" />
|
||||
{{ p.status }}
|
||||
|
@ -29,7 +29,7 @@ interface AccountCreateAttributes {
|
||||
|
||||
interface PlaylistAttributes {
|
||||
id: number
|
||||
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'completed' | 'failed'
|
||||
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'decrypting' | 'completed' | 'failed'
|
||||
media: CrunchyEpisode | ADNEpisode
|
||||
dub: Array<string>
|
||||
sub: Array<string>
|
||||
@ -48,7 +48,7 @@ interface PlaylistCreateAttributes {
|
||||
dir: string
|
||||
quality: 1080 | 720 | 480 | 360 | 240
|
||||
hardsub: boolean
|
||||
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'completed' | 'failed'
|
||||
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'decrypting' | 'completed' | 'failed'
|
||||
service: 'CR' | 'ADN'
|
||||
format: 'mp4' | 'mkv'
|
||||
}
|
||||
|
@ -149,11 +149,12 @@ export async function crunchyGetPlaylistDRM(q: string) {
|
||||
if (!login) return
|
||||
|
||||
const headers = {
|
||||
Authorization: `Bearer ${login.access_token}`
|
||||
Authorization: `Bearer ${login.access_token}`,
|
||||
'x-cr-stream-limits': 'false'
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://cr-play-service.prd.crunchyrollsvc.com/v1/${q}/web/chrome/play`, {
|
||||
const response = await fetch(`https://cr-play-service.prd.crunchyrollsvc.com/v1/${q}/tv/samsung/play`, {
|
||||
method: 'GET',
|
||||
headers: headers
|
||||
})
|
||||
@ -174,6 +175,36 @@ export async function crunchyGetPlaylistDRM(q: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteVideoToken(content: string, token: string) {
|
||||
const account = await loggedInCheck('CR')
|
||||
|
||||
if (!account) return
|
||||
|
||||
const { data: login, error } = await crunchyLogin(account.username, account.password)
|
||||
|
||||
if (!login) return
|
||||
|
||||
const headers = {
|
||||
Authorization: `Bearer ${login.access_token}`,
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://cr-play-service.prd.crunchyrollsvc.com/v1/token/${content}/${token}`, {
|
||||
method: 'DELETE',
|
||||
headers: headers
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
return 'ok'
|
||||
} else {
|
||||
throw new Error(await response.text())
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Delete token failed')
|
||||
throw new Error(e as string)
|
||||
}
|
||||
}
|
||||
|
||||
export async function crunchyGetPlaylistMPD(q: string) {
|
||||
const account = await loggedInCheck('CR')
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { concatenateTSFiles } from '../../services/concatenate'
|
||||
import { createFolder, createFolderName, deleteFolder, deleteTemporaryFolders } from '../../services/folder'
|
||||
import { downloadADNSub, downloadCRSub } from '../../services/subs'
|
||||
import { CrunchyEpisode } from '../../types/crunchyroll'
|
||||
import { crunchyGetPlaylist, crunchyGetPlaylistDRM, crunchyGetPlaylistMPD } from '../crunchyroll/crunchyroll.service'
|
||||
import { crunchyGetPlaylist, crunchyGetPlaylistDRM, crunchyGetPlaylistMPD, deleteVideoToken } from '../crunchyroll/crunchyroll.service'
|
||||
import fs from 'fs'
|
||||
var cron = require('node-cron')
|
||||
import { Readable } from 'stream'
|
||||
@ -60,7 +60,7 @@ async function deletePlaylistandTMP() {
|
||||
deletePlaylistandTMP()
|
||||
|
||||
// Update Playlist Item
|
||||
export async function updatePlaylistByID(id: number, status: 'waiting' | 'preparing' | 'downloading' | 'completed' | 'merging' | 'failed') {
|
||||
export async function updatePlaylistByID(id: number, status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'decrypting' | 'completed' | 'failed') {
|
||||
await Playlist.update({ status: status }, { where: { id: id } })
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ export async function addEpisodeToPlaylist(
|
||||
d: Array<string>,
|
||||
dir: string,
|
||||
hardsub: boolean,
|
||||
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'completed' | 'failed',
|
||||
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'decrypting' | 'completed' | 'failed',
|
||||
quality: 1080 | 720 | 480 | 360 | 240,
|
||||
service: 'CR' | 'ADN',
|
||||
format: 'mp4' | 'mkv'
|
||||
@ -150,6 +150,7 @@ async function checkPlaylists() {
|
||||
(e as any).dataValues.dub.map((s: { locale: any }) => s.locale),
|
||||
(e as any).dataValues.sub.map((s: { locale: any }) => s.locale),
|
||||
e.dataValues.hardsub,
|
||||
(e.dataValues.media as CrunchyEpisode).id,
|
||||
e.dataValues.id,
|
||||
(e.dataValues.media as CrunchyEpisode).series_title,
|
||||
(e.dataValues.media as CrunchyEpisode).season_number,
|
||||
@ -308,6 +309,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
dubs: Array<string>,
|
||||
subs: Array<string>,
|
||||
hardsub: boolean,
|
||||
episodeID: string,
|
||||
downloadID: number,
|
||||
name: string,
|
||||
season: number,
|
||||
@ -325,7 +327,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
|
||||
await updatePlaylistByID(downloadID, 'downloading')
|
||||
|
||||
var playlist = await crunchyGetPlaylist(e)
|
||||
var playlist = await crunchyGetPlaylistDRM(e)
|
||||
|
||||
if (!playlist) {
|
||||
console.log('Playlist not found')
|
||||
@ -336,7 +338,8 @@ export async function downloadCrunchyrollPlaylist(
|
||||
if (playlist.data.audioLocale !== subs[0]) {
|
||||
const found = playlist.data.versions.find((v) => v.audio_locale === 'ja-JP')
|
||||
if (found) {
|
||||
playlist = await crunchyGetPlaylist(found.guid)
|
||||
await deleteVideoToken(episodeID, playlist.data.token)
|
||||
playlist = await crunchyGetPlaylistDRM(found.guid)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -346,6 +349,8 @@ export async function downloadCrunchyrollPlaylist(
|
||||
return
|
||||
}
|
||||
|
||||
await deleteVideoToken(episodeID, playlist.data.token)
|
||||
|
||||
const subFolder = await createFolder()
|
||||
|
||||
const audioFolder = await createFolder()
|
||||
@ -395,6 +400,8 @@ export async function downloadCrunchyrollPlaylist(
|
||||
} else {
|
||||
console.warn(`Subtitle ${s}.ass not found, skipping`)
|
||||
}
|
||||
|
||||
await deleteVideoToken(episodeID, playlist.data.token)
|
||||
}
|
||||
|
||||
for (const d of dubs) {
|
||||
@ -412,6 +419,8 @@ export async function downloadCrunchyrollPlaylist(
|
||||
} else {
|
||||
console.log(`No Dub Sub Found for ${d}`)
|
||||
}
|
||||
|
||||
await deleteVideoToken(episodeID, playlist.data.token)
|
||||
}
|
||||
dubDownloadList.push(found)
|
||||
console.log(`Audio ${d}.aac found, adding to download`)
|
||||
@ -465,9 +474,16 @@ export async function downloadCrunchyrollPlaylist(
|
||||
|
||||
if (!playlist) return
|
||||
|
||||
const assetId = playlist.mediaGroups.AUDIO.audio.main.playlists[0].segments[0].uri.match(/\/assets\/(?:p\/)?([^_,]+)/)
|
||||
await deleteVideoToken(episodeID, list.data.token)
|
||||
|
||||
if (!assetId) return
|
||||
const assetId = playlist.mediaGroups.AUDIO.audio.main.playlists[0].segments[0].resolvedUri.match(/\/assets\/(?:p\/)?([^_,]+)/)
|
||||
|
||||
if (!assetId) {
|
||||
console.log(playlist.mediaGroups.AUDIO.audio.main.playlists[0].segments[0])
|
||||
console.log(playlist.mediaGroups.AUDIO.audio.main.playlists[0].segments[0].uri)
|
||||
console.log('No AssetID found, exiting.')
|
||||
return
|
||||
}
|
||||
|
||||
var pssh
|
||||
var keys: { kid: string; key: string }[] | undefined
|
||||
@ -475,7 +491,10 @@ export async function downloadCrunchyrollPlaylist(
|
||||
var p: { filename: string; url: string }[] = []
|
||||
|
||||
if (playlist.mediaGroups.AUDIO.audio.main.playlists[0].contentProtection) {
|
||||
if (!playlist.mediaGroups.AUDIO.audio.main.playlists[0].contentProtection['com.widevine.alpha'].pssh) return
|
||||
if (!playlist.mediaGroups.AUDIO.audio.main.playlists[0].contentProtection['com.widevine.alpha'].pssh) {
|
||||
console.log('No PSSH found, exiting.')
|
||||
return
|
||||
}
|
||||
pssh = Uint8ArrayToBase64(playlist.mediaGroups.AUDIO.audio.main.playlists[0].contentProtection['com.widevine.alpha'].pssh)
|
||||
|
||||
keys = await getDRMKeys(pssh, assetId[1], list.account_id)
|
||||
@ -542,19 +561,27 @@ export async function downloadCrunchyrollPlaylist(
|
||||
|
||||
if (!mdp) return
|
||||
|
||||
await deleteVideoToken(episodeID, play.data.token)
|
||||
|
||||
var hq = mdp.playlists.find((i) => i.attributes.RESOLUTION?.height === quality)
|
||||
|
||||
if (!hq) return
|
||||
|
||||
const assetId = hq.segments[0].uri.match(/\/assets\/(?:p\/)?([^_,]+)/)
|
||||
const assetId = hq.segments[0].resolvedUri.match(/\/assets\/(?:p\/)?([^_,]+)/)
|
||||
|
||||
if (!assetId) return
|
||||
if (!assetId) {
|
||||
console.log('No AssetID found, exiting.')
|
||||
return
|
||||
}
|
||||
|
||||
var pssh
|
||||
var keys: { kid: string; key: string }[] | undefined
|
||||
|
||||
if (hq.contentProtection) {
|
||||
if (!hq.contentProtection['com.widevine.alpha'].pssh) return
|
||||
if (!hq.contentProtection['com.widevine.alpha'].pssh) {
|
||||
console.log('No PSSH found, exiting.')
|
||||
return
|
||||
}
|
||||
pssh = Uint8ArrayToBase64(hq.contentProtection['com.widevine.alpha'].pssh)
|
||||
|
||||
keys = await getDRMKeys(pssh, assetId[1], play.account_id)
|
||||
@ -670,13 +697,16 @@ async function mergeParts(parts: { filename: string; url: string }[], downloadID
|
||||
await concatenateTSFiles(list, concatenatedFile)
|
||||
|
||||
if (drmkeys) {
|
||||
await updatePlaylistByID(downloadID, 'decrypting')
|
||||
console.log('Video Decryption started')
|
||||
const inputFilePath = `${tmp}/temp-main.m4s`
|
||||
const outputFilePath = `${tmp}/main.m4s`
|
||||
const keyArgument = `--show-progress --key ${drmkeys[1].kid}:${drmkeys[1].key}`
|
||||
|
||||
const command = `${mp4e} ${keyArgument} "${inputFilePath}" "${outputFilePath}"`
|
||||
|
||||
const { stdout, stderr } = await exec(command)
|
||||
await exec(command)
|
||||
console.log('Video Decryption finished')
|
||||
concatenatedFile = `${tmp}/main.m4s`
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user