added more downloading info (audio downloading, more statuses)
This commit is contained in:
parent
60fde780fe
commit
20fc3c2ac5
@ -18,6 +18,7 @@
|
|||||||
<div class="flex flex-col w-full">
|
<div class="flex flex-col w-full">
|
||||||
<div class="flex flex-row h-full">
|
<div class="flex flex-row h-full">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
|
<div class="flex flex-row">
|
||||||
<div v-if="p.status === 'failed'" class="flex flex-row items-center justify-center gap-1 text-xs capitalize p-1.5 bg-[#863232] rounded-lg">
|
<div v-if="p.status === 'failed'" class="flex flex-row items-center justify-center gap-1 text-xs capitalize p-1.5 bg-[#863232] rounded-lg">
|
||||||
<Icon name="bitcoin-icons:cross-filled" class="h-3.5 w-3.5 text-white" />
|
<Icon name="bitcoin-icons:cross-filled" class="h-3.5 w-3.5 text-white" />
|
||||||
{{ p.status }}
|
{{ p.status }}
|
||||||
@ -30,15 +31,44 @@
|
|||||||
<Icon name="mdi:clock" class="h-3.5 w-3.5 text-white" />
|
<Icon name="mdi:clock" class="h-3.5 w-3.5 text-white" />
|
||||||
{{ p.status }}
|
{{ p.status }}
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="p.status === 'waiting for playlist'"
|
||||||
|
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 === 'waiting for sub playlist'"
|
||||||
|
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 === 'waiting for dub playlist'"
|
||||||
|
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 === 'downloading'" class="flex flex-row items-center justify-center gap-1 text-xs capitalize p-1.5 bg-[#60501b] rounded-lg">
|
<div v-if="p.status === 'downloading'" class="flex flex-row items-center justify-center gap-1 text-xs capitalize p-1.5 bg-[#60501b] rounded-lg">
|
||||||
<Icon name="mdi:loading" class="h-3.5 w-3.5 text-white animate-spin" />
|
<Icon name="mdi:loading" class="h-3.5 w-3.5 text-white animate-spin" />
|
||||||
{{ p.status }}
|
{{ p.status }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="p.status === 'merging'" class="flex flex-row items-center justify-center gap-1 text-xs capitalize p-1.5 bg-[#866332] rounded-lg">
|
<div v-if="p.status === 'merging video'" 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" />
|
<Icon name="mdi:loading" class="h-3.5 w-3.5 text-white animate-spin" />
|
||||||
{{ p.status }}
|
{{ p.status }}
|
||||||
</div>
|
</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">
|
<div v-if="p.status === 'decrypting video'" 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 === 'awaiting all dubs downloaded'" 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 === 'merging video & audio'" 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" />
|
<Icon name="mdi:loading" class="h-3.5 w-3.5 text-white animate-spin" />
|
||||||
{{ p.status }}
|
{{ p.status }}
|
||||||
</div>
|
</div>
|
||||||
@ -46,6 +76,13 @@
|
|||||||
<Icon name="material-symbols:check" class="h-3.5 w-3.5 text-white" />
|
<Icon name="material-symbols:check" class="h-3.5 w-3.5 text-white" />
|
||||||
{{ p.status }}
|
{{ p.status }}
|
||||||
</div>
|
</div>
|
||||||
|
<div v-for="a in p.audiosdownloading">
|
||||||
|
<div v-if="a.status && a.audio && a.status !== 'finished'" class="ml-2 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" />
|
||||||
|
{{ a.status }} Audio {{ a.audio }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs capitalize ml-auto">
|
<div class="text-xs capitalize ml-auto">
|
||||||
{{ p.service === 'CR' ? 'Crunchyroll' : 'ADN' }}
|
{{ p.service === 'CR' ? 'Crunchyroll' : 'ADN' }}
|
||||||
@ -63,7 +100,7 @@
|
|||||||
<div class="text-xs">{{ p.quality }}p</div>
|
<div class="text-xs">{{ p.quality }}p</div>
|
||||||
<div class="text-xs uppercase">{{ p.format }}</div>
|
<div class="text-xs uppercase">{{ p.format }}</div>
|
||||||
<div class="text-xs">Dubs: {{ p.dub.map((t) => t.name).join(', ') }}</div>
|
<div class="text-xs">Dubs: {{ p.dub.map((t) => t.name).join(', ') }}</div>
|
||||||
<div class="text-xs mr-14">Subs: {{ p.sub.length !== 0 ? p.sub.map((t) => t.name).join(', ') : '-' }}</div>
|
<div class="text-xs mr-20">Subs: {{ p.sub.length !== 0 ? p.sub.map((t) => t.name).join(', ') : '-' }}</div>
|
||||||
<div class="absolute flex flex-col ml-auto gap-0.5 right-0 bottom-0">
|
<div class="absolute flex flex-col ml-auto gap-0.5 right-0 bottom-0">
|
||||||
<div v-if="p.totaldownloaded && p.status === 'downloading'" class="text-xs ml-auto"
|
<div v-if="p.totaldownloaded && p.status === 'downloading'" class="text-xs ml-auto"
|
||||||
>{{ (p.totaldownloaded / Math.pow(1024, 2)).toFixed(2) }} MB</div
|
>{{ (p.totaldownloaded / Math.pow(1024, 2)).toFixed(2) }} MB</div
|
||||||
@ -103,6 +140,10 @@ const playlist = ref<
|
|||||||
quality: number
|
quality: number
|
||||||
service: string
|
service: string
|
||||||
format: string
|
format: string
|
||||||
|
audiosdownloading: {
|
||||||
|
status: string,
|
||||||
|
audio: string
|
||||||
|
}[]
|
||||||
}>
|
}>
|
||||||
>()
|
>()
|
||||||
|
|
||||||
@ -123,6 +164,10 @@ const getPlaylist = async () => {
|
|||||||
quality: number
|
quality: number
|
||||||
service: string
|
service: string
|
||||||
format: string
|
format: string
|
||||||
|
audiosdownloading: {
|
||||||
|
status: string,
|
||||||
|
audio: string
|
||||||
|
}[]
|
||||||
}>
|
}>
|
||||||
>('http://localhost:9941/api/service/playlist')
|
>('http://localhost:9941/api/service/playlist')
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ interface AccountCreateAttributes {
|
|||||||
|
|
||||||
interface PlaylistAttributes {
|
interface PlaylistAttributes {
|
||||||
id: number
|
id: number
|
||||||
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'decrypting' | 'completed' | 'failed'
|
status: 'waiting' | 'preparing' | 'waiting for playlist' | 'waiting for sub playlist' | 'waiting for dub playlist' | 'downloading' | 'merging video' | 'decrypting video' | 'awaiting all dubs downloaded' | 'merging video & audio' | 'completed' | 'failed'
|
||||||
media: CrunchyEpisode | ADNEpisode
|
media: CrunchyEpisode | ADNEpisode
|
||||||
dub: Array<string>
|
dub: Array<string>
|
||||||
sub: Array<string>
|
sub: Array<string>
|
||||||
@ -49,7 +49,7 @@ interface PlaylistCreateAttributes {
|
|||||||
dir: string
|
dir: string
|
||||||
quality: 1080 | 720 | 480 | 360 | 240
|
quality: 1080 | 720 | 480 | 360 | 240
|
||||||
hardsub: boolean
|
hardsub: boolean
|
||||||
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'decrypting' | 'completed' | 'failed'
|
status: 'waiting' | 'preparing' | 'waiting for playlist' | 'waiting for sub playlist' | 'waiting for dub playlist' | 'downloading' | 'merging video' | 'decrypting video' | 'awaiting all dubs downloaded' | 'merging video & audio' | 'completed' | 'failed'
|
||||||
service: 'CR' | 'ADN'
|
service: 'CR' | 'ADN'
|
||||||
format: 'mp4' | 'mkv'
|
format: 'mp4' | 'mkv'
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import { addEpisodeToPlaylist, deleteAccountID, getAllAccounts, getDownloading,
|
|||||||
import { CrunchyEpisodes } from '../../types/crunchyroll'
|
import { CrunchyEpisodes } from '../../types/crunchyroll'
|
||||||
import { adnLogin } from '../adn/adn.service'
|
import { adnLogin } from '../adn/adn.service'
|
||||||
import { server } from '../../api'
|
import { server } from '../../api'
|
||||||
|
import { getDownloadingAudio } from '../../services/audio'
|
||||||
|
|
||||||
export async function checkLoginController(
|
export async function checkLoginController(
|
||||||
request: FastifyRequest<{
|
request: FastifyRequest<{
|
||||||
@ -121,8 +122,9 @@ export async function getPlaylistController(request: FastifyRequest, reply: Fast
|
|||||||
if (!playlist) return
|
if (!playlist) return
|
||||||
|
|
||||||
for (const v of playlist) {
|
for (const v of playlist) {
|
||||||
if (v.dataValues.status === 'downloading') {
|
if (v.dataValues.status !== 'completed') {
|
||||||
const found = await getDownloading(v.dataValues.id)
|
const found = await getDownloading(v.dataValues.id)
|
||||||
|
const foundAudio = await getDownloadingAudio(v.dataValues.id)
|
||||||
if (found) {
|
if (found) {
|
||||||
;(v as any).dataValues = {
|
;(v as any).dataValues = {
|
||||||
...v.dataValues,
|
...v.dataValues,
|
||||||
@ -132,6 +134,12 @@ export async function getPlaylistController(request: FastifyRequest, reply: Fast
|
|||||||
totaldownloaded: found.totalDownloaded
|
totaldownloaded: found.totalDownloaded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (foundAudio) {
|
||||||
|
;(v as any).dataValues = {
|
||||||
|
...v.dataValues,
|
||||||
|
audiosdownloading: foundAudio
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ deletePlaylistandTMP();
|
|||||||
// Update Playlist Item
|
// Update Playlist Item
|
||||||
export async function updatePlaylistByID(
|
export async function updatePlaylistByID(
|
||||||
id: number,
|
id: number,
|
||||||
status?: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'decrypting' | 'completed' | 'failed',
|
status?: 'waiting' | 'preparing' | 'waiting for playlist' | 'waiting for sub playlist' | 'waiting for dub playlist' | 'downloading' | 'merging video' | 'decrypting video' | 'awaiting all dubs downloaded' | 'merging video & audio' | 'completed' | 'failed',
|
||||||
quality?: 1080 | 720 | 480 | 360 | 240,
|
quality?: 1080 | 720 | 480 | 360 | 240,
|
||||||
installedDir?: string
|
installedDir?: string
|
||||||
) {
|
) {
|
||||||
@ -199,7 +199,7 @@ export async function addEpisodeToPlaylist(
|
|||||||
d: Array<string>,
|
d: Array<string>,
|
||||||
dir: string,
|
dir: string,
|
||||||
hardsub: boolean,
|
hardsub: boolean,
|
||||||
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'decrypting' | 'completed' | 'failed',
|
status: 'waiting' | 'preparing' | 'waiting for playlist' | 'waiting for sub playlist' | 'waiting for dub playlist' | 'downloading' | 'merging video' | 'decrypting video' | 'awaiting all dubs downloaded' | 'merging video & audio' | 'completed' | 'failed',
|
||||||
quality: 1080 | 720 | 480 | 360 | 240,
|
quality: 1080 | 720 | 480 | 360 | 240,
|
||||||
service: 'CR' | 'ADN',
|
service: 'CR' | 'ADN',
|
||||||
format: 'mp4' | 'mkv'
|
format: 'mp4' | 'mkv'
|
||||||
@ -222,6 +222,7 @@ export async function addEpisodeToPlaylist(
|
|||||||
// Define Downloading Array
|
// Define Downloading Array
|
||||||
var downloading: Array<{
|
var downloading: Array<{
|
||||||
id: number
|
id: number
|
||||||
|
status: string
|
||||||
downloadedParts: number
|
downloadedParts: number
|
||||||
partsToDownload: number
|
partsToDownload: number
|
||||||
downloadSpeed: number
|
downloadSpeed: number
|
||||||
@ -318,6 +319,7 @@ export async function downloadADNPlaylist(
|
|||||||
) {
|
) {
|
||||||
downloading.push({
|
downloading.push({
|
||||||
id: downloadID,
|
id: downloadID,
|
||||||
|
status: 'downloading',
|
||||||
downloadedParts: 0,
|
downloadedParts: 0,
|
||||||
partsToDownload: 0,
|
partsToDownload: 0,
|
||||||
downloadSpeed: 0,
|
downloadSpeed: 0,
|
||||||
@ -462,13 +464,6 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
format: 'mp4' | 'mkv',
|
format: 'mp4' | 'mkv',
|
||||||
geo: string | undefined
|
geo: string | undefined
|
||||||
) {
|
) {
|
||||||
downloading.push({
|
|
||||||
id: downloadID,
|
|
||||||
downloadedParts: 0,
|
|
||||||
partsToDownload: 0,
|
|
||||||
downloadSpeed: 0,
|
|
||||||
totalDownloaded: 0
|
|
||||||
})
|
|
||||||
|
|
||||||
const accmaxstream = await checkAccountMaxStreams();
|
const accmaxstream = await checkAccountMaxStreams();
|
||||||
|
|
||||||
@ -476,7 +471,7 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
maxLimit = accmaxstream
|
maxLimit = accmaxstream
|
||||||
}
|
}
|
||||||
|
|
||||||
await updatePlaylistByID(downloadID, 'downloading')
|
await updatePlaylistByID(downloadID, 'waiting for playlist')
|
||||||
|
|
||||||
await incrementPlaylistCounter();
|
await incrementPlaylistCounter();
|
||||||
var playlist = await crunchyGetPlaylist(e, geo)
|
var playlist = await crunchyGetPlaylist(e, geo)
|
||||||
@ -562,6 +557,8 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
isDub: boolean
|
isDub: boolean
|
||||||
}> = []
|
}> = []
|
||||||
|
|
||||||
|
await updatePlaylistByID(downloadID, 'waiting for sub playlist')
|
||||||
|
|
||||||
for (const s of subs) {
|
for (const s of subs) {
|
||||||
var subPlaylist
|
var subPlaylist
|
||||||
|
|
||||||
@ -612,6 +609,8 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
decrementPlaylistCounter()
|
decrementPlaylistCounter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await updatePlaylistByID(downloadID, 'waiting for dub playlist')
|
||||||
|
|
||||||
for (const d of dubs) {
|
for (const d of dubs) {
|
||||||
var found
|
var found
|
||||||
if (playlist.data.versions) {
|
if (playlist.data.versions) {
|
||||||
@ -665,6 +664,8 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await updatePlaylistByID(downloadID, 'downloading')
|
||||||
|
|
||||||
const subDownload = async () => {
|
const subDownload = async () => {
|
||||||
const sbs: Array<string> = []
|
const sbs: Array<string> = []
|
||||||
for (const sub of subDownloadList) {
|
for (const sub of subDownloadList) {
|
||||||
@ -756,7 +757,7 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = await downloadMPDAudio(p, audioFolder, list.data.audioLocale, keys ? keys : undefined)
|
const path = await downloadMPDAudio(p, audioFolder, list.data.audioLocale, downloadID, keys ? keys : undefined)
|
||||||
|
|
||||||
audios.push(path as string)
|
audios.push(path as string)
|
||||||
}
|
}
|
||||||
@ -764,6 +765,16 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const downloadVideo = async () => {
|
const downloadVideo = async () => {
|
||||||
|
|
||||||
|
downloading.push({
|
||||||
|
id: downloadID,
|
||||||
|
status: 'Waiting for Playlist',
|
||||||
|
downloadedParts: 0,
|
||||||
|
partsToDownload: 0,
|
||||||
|
downloadSpeed: 0,
|
||||||
|
totalDownloaded: 0
|
||||||
|
})
|
||||||
|
|
||||||
var code
|
var code
|
||||||
|
|
||||||
if (!playlist) return
|
if (!playlist) return
|
||||||
@ -949,6 +960,8 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
|
|
||||||
const file = await downloadParts(p, downloadID, videoFolder, keys ? keys : undefined)
|
const file = await downloadParts(p, downloadID, videoFolder, keys ? keys : undefined)
|
||||||
|
|
||||||
|
await updatePlaylistByID(downloadID, 'awaiting all dubs downloaded')
|
||||||
|
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,6 +969,7 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
|
|
||||||
if (!audios) return
|
if (!audios) return
|
||||||
|
|
||||||
|
await updatePlaylistByID(downloadID, 'merging video & audio')
|
||||||
await mergeVideoFile(file as string, audios, subss, seasonFolder, `${name.replace(/[/\\?%*:|"<>]/g, '')} Season ${season} Episode ${episode}`, format, downloadID)
|
await mergeVideoFile(file as string, audios, subss, seasonFolder, `${name.replace(/[/\\?%*:|"<>]/g, '')} Season ${season} Episode ${episode}`, format, downloadID)
|
||||||
|
|
||||||
await updatePlaylistByID(downloadID, 'completed')
|
await updatePlaylistByID(downloadID, 'completed')
|
||||||
@ -1039,7 +1053,7 @@ async function mergeParts(parts: { filename: string; url: string }[], downloadID
|
|||||||
try {
|
try {
|
||||||
const list: Array<string> = []
|
const list: Array<string> = []
|
||||||
|
|
||||||
await updatePlaylistByID(downloadID, 'merging')
|
await updatePlaylistByID(downloadID, 'merging video')
|
||||||
isDownloading--
|
isDownloading--
|
||||||
|
|
||||||
for (const [index, part] of parts.entries()) {
|
for (const [index, part] of parts.entries()) {
|
||||||
@ -1057,7 +1071,7 @@ async function mergeParts(parts: { filename: string; url: string }[], downloadID
|
|||||||
await concatenateTSFiles(list, concatenatedFile)
|
await concatenateTSFiles(list, concatenatedFile)
|
||||||
|
|
||||||
if (drmkeys) {
|
if (drmkeys) {
|
||||||
await updatePlaylistByID(downloadID, 'decrypting')
|
await updatePlaylistByID(downloadID, 'decrypting video')
|
||||||
console.log('Video Decryption started')
|
console.log('Video Decryption started')
|
||||||
const inputFilePath = `${tmp}/temp-main.m4s`
|
const inputFilePath = `${tmp}/temp-main.m4s`
|
||||||
const outputFilePath = `${tmp}/main.m4s`
|
const outputFilePath = `${tmp}/main.m4s`
|
||||||
|
@ -8,11 +8,39 @@ import { getMP4DecryptPath } from '../services/mp4decrypt'
|
|||||||
const ffmpegP = getFFMPEGPath()
|
const ffmpegP = getFFMPEGPath()
|
||||||
const mp4e = getMP4DecryptPath()
|
const mp4e = getMP4DecryptPath()
|
||||||
import util from 'util'
|
import util from 'util'
|
||||||
|
import { server } from '../api'
|
||||||
const exec = util.promisify(require('child_process').exec)
|
const exec = util.promisify(require('child_process').exec)
|
||||||
|
|
||||||
export async function downloadMPDAudio(parts: { filename: string; url: string }[], dir: string, name: string, drmkeys?: { kid: string; key: string }[] | undefined) {
|
// Define Downloading Array
|
||||||
|
var downloading: Array<{
|
||||||
|
id: number
|
||||||
|
status: string
|
||||||
|
audio: string
|
||||||
|
}> = []
|
||||||
|
|
||||||
|
export async function getDownloadingAudio(id: number) {
|
||||||
|
const found = downloading.filter((i) => i.id === id)
|
||||||
|
|
||||||
|
if (found) return found
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function downloadMPDAudio(
|
||||||
|
parts: { filename: string; url: string }[],
|
||||||
|
dir: string,
|
||||||
|
name: string,
|
||||||
|
downloadID: number,
|
||||||
|
drmkeys?: { kid: string; key: string }[] | undefined
|
||||||
|
) {
|
||||||
const path = await createFolder()
|
const path = await createFolder()
|
||||||
|
|
||||||
|
downloading.push({
|
||||||
|
id: downloadID,
|
||||||
|
status: `downloading`,
|
||||||
|
audio: name
|
||||||
|
})
|
||||||
|
|
||||||
const maxParallelDownloads = 5
|
const maxParallelDownloads = 5
|
||||||
const downloadPromises = []
|
const downloadPromises = []
|
||||||
|
|
||||||
@ -42,11 +70,41 @@ export async function downloadMPDAudio(parts: { filename: string; url: string }[
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await mergePartsAudio(parts, path, dir, name, drmkeys)
|
return await mergePartsAudio(parts, path, dir, name, downloadID, drmkeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAndPipe(url: string, stream: fs.WriteStream, index: number) {
|
async function fetchAndPipe(url: string, stream: fs.WriteStream, index: number) {
|
||||||
const { body } = await fetch(url)
|
try {
|
||||||
|
const response = await fetch(url)
|
||||||
|
|
||||||
|
// Check if fetch was successful
|
||||||
|
if (!response.ok) {
|
||||||
|
server.logger.log({
|
||||||
|
level: 'error',
|
||||||
|
message: 'Error while downloading an Audio Fragment',
|
||||||
|
fragment: index,
|
||||||
|
error: await response.text(),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
section: 'audiofragmentCrunchyrollFetch'
|
||||||
|
})
|
||||||
|
throw new Error(`Failed to fetch URL: ${response.statusText}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = response.body
|
||||||
|
|
||||||
|
// Check if the body exists and is readable
|
||||||
|
if (!body) {
|
||||||
|
server.logger.log({
|
||||||
|
level: 'error',
|
||||||
|
message: 'Error while downloading an Audio Fragment',
|
||||||
|
fragment: index,
|
||||||
|
error: 'Response body is not a readable stream',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
section: 'audiofragmentCrunchyrollFetch'
|
||||||
|
})
|
||||||
|
throw new Error('Response body is not a readable stream')
|
||||||
|
}
|
||||||
|
|
||||||
const readableStream = Readable.from(body as any)
|
const readableStream = Readable.from(body as any)
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
@ -57,12 +115,44 @@ async function fetchAndPipe(url: string, stream: fs.WriteStream, index: number)
|
|||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
.on('error', (error) => {
|
.on('error', (error) => {
|
||||||
|
server.logger.log({
|
||||||
|
level: 'error',
|
||||||
|
message: 'Error while downloading an Audio Fragment',
|
||||||
|
fragment: index,
|
||||||
|
error: error,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
section: 'audiofragmentCrunchyrollFetch'
|
||||||
|
})
|
||||||
reject(error)
|
reject(error)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
} catch (error) {
|
||||||
|
server.logger.log({
|
||||||
|
level: 'error',
|
||||||
|
message: 'Error while downloading an Audio Fragment',
|
||||||
|
fragment: index,
|
||||||
|
error: error,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
section: 'audiofragmentCrunchyrollFetch'
|
||||||
|
})
|
||||||
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function mergePartsAudio(parts: { filename: string; url: string }[], tmp: string, dir: string, name: string, drmkeys?: { kid: string; key: string }[] | undefined) {
|
async function mergePartsAudio(
|
||||||
|
parts: { filename: string; url: string }[],
|
||||||
|
tmp: string,
|
||||||
|
dir: string,
|
||||||
|
name: string,
|
||||||
|
downloadID: number,
|
||||||
|
drmkeys?: { kid: string; key: string }[] | undefined
|
||||||
|
) {
|
||||||
|
const dn = downloading.find((i) => i.id === downloadID && i.audio === name)
|
||||||
|
|
||||||
|
if (dn) {
|
||||||
|
dn.status = 'merging'
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const list: Array<string> = []
|
const list: Array<string> = []
|
||||||
|
|
||||||
@ -81,6 +171,9 @@ async function mergePartsAudio(parts: { filename: string; url: string }[], tmp:
|
|||||||
await concatenateTSFiles(list, concatenatedFile)
|
await concatenateTSFiles(list, concatenatedFile)
|
||||||
|
|
||||||
if (drmkeys) {
|
if (drmkeys) {
|
||||||
|
if (dn) {
|
||||||
|
dn.status = 'decrypting'
|
||||||
|
}
|
||||||
console.log(`Audio Decryption started`)
|
console.log(`Audio Decryption started`)
|
||||||
const inputFilePath = `${tmp}/temp-main.m4s`
|
const inputFilePath = `${tmp}/temp-main.m4s`
|
||||||
const outputFilePath = `${tmp}/main.m4s`
|
const outputFilePath = `${tmp}/main.m4s`
|
||||||
@ -105,6 +198,10 @@ async function mergePartsAudio(parts: { filename: string; url: string }[], tmp:
|
|||||||
console.log('Merging finished')
|
console.log('Merging finished')
|
||||||
await deleteFolder(tmp)
|
await deleteFolder(tmp)
|
||||||
|
|
||||||
|
if (dn) {
|
||||||
|
dn.status = 'finished'
|
||||||
|
}
|
||||||
|
|
||||||
return resolve(`${dir}/${name}.aac`)
|
return resolve(`${dir}/${name}.aac`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user