From 3567edae4b362cb3644d3385b952bec9578a6ce1 Mon Sep 17 00:00:00 2001 From: AnimeDL Date: Tue, 9 Apr 2024 14:37:21 -0700 Subject: [PATCH] Use temp file for decryption Fixes issue with unicode and path length limits --- crunchy.ts | 18 ++++++++++++------ hidive.ts | 22 +++++++++++++++------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/crunchy.ts b/crunchy.ts index 370e445..47c35e8 100644 --- a/crunchy.ts +++ b/crunchy.ts @@ -1635,6 +1635,8 @@ export default class Crunchy implements ServiceClass { // TODO check filename fileName = parseFileName(options.fileName, variables, options.numbers, options.override).join(path.sep); const outFile = parseFileName(options.fileName + '.' + (mMeta.lang?.name || lang.name), variables, options.numbers, options.override).join(path.sep); + const tempFile = parseFileName(`temp-${currentVersion ? currentVersion.guid : mMeta.mediaId}`, variables, options.numbers, options.override).join(path.sep); + const tempTsFile = path.isAbsolute(tempFile as string) ? tempFile : path.join(this.cfg.dir.content, tempFile); let [audioDownloaded, videoDownloaded] = [false, false]; @@ -1660,7 +1662,7 @@ export default class Crunchy implements ServiceClass { segments: chosenVideoSegments.segments }; const videoDownload = await new streamdl({ - output: chosenVideoSegments.pssh ? `${tsFile}.video.enc.m4s` : `${tsFile}.video.m4s`, + output: chosenVideoSegments.pssh ? `${tempTsFile}.video.enc.m4s` : `${tsFile}.video.m4s`, timeout: options.timeout, m3u8json: videoJson, // baseurl: chunkPlaylist.baseUrl, @@ -1702,7 +1704,7 @@ export default class Crunchy implements ServiceClass { segments: chosenAudioSegments.segments }; const audioDownload = await new streamdl({ - output: chosenAudioSegments.pssh ? `${tsFile}.audio.enc.m4s` : `${tsFile}.audio.m4s`, + output: chosenAudioSegments.pssh ? `${tempTsFile}.audio.enc.m4s` : `${tsFile}.audio.m4s`, timeout: options.timeout, m3u8json: audioJson, // baseurl: chunkPlaylist.baseUrl, @@ -1764,8 +1766,8 @@ export default class Crunchy implements ServiceClass { if (this.cfg.bin.mp4decrypt) { const commandBase = `--show-progress --key ${encryptionKeys[1].kid}:${encryptionKeys[1].key} `; - const commandVideo = commandBase+`"${tsFile}.video.enc.m4s" "${tsFile}.video.m4s"`; - const commandAudio = commandBase+`"${tsFile}.audio.enc.m4s" "${tsFile}.audio.m4s"`; + const commandVideo = commandBase+`"${tempTsFile}.video.enc.m4s" "${tempTsFile}.video.m4s"`; + const commandAudio = commandBase+`"${tempTsFile}.audio.enc.m4s" "${tempTsFile}.audio.m4s"`; if (videoDownloaded) { console.info('Started decrypting video'); @@ -1773,12 +1775,14 @@ export default class Crunchy implements ServiceClass { if (!decryptVideo.isOk) { console.error(decryptVideo.err); console.error(`Decryption failed with exit code ${decryptVideo.err.code}`); + fs.renameSync(`${tempTsFile}.video.enc.m4s`, `${tsFile}.video.enc.m4s`); return undefined; } else { console.info('Decryption done for video'); if (!options.nocleanup) { - fs.removeSync(`${tsFile}.video.enc.m4s`); + fs.removeSync(`${tempTsFile}.video.enc.m4s`); } + fs.renameSync(`${tempTsFile}.video.m4s`, `${tsFile}.video.m4s`); files.push({ type: 'Video', path: `${tsFile}.video.m4s`, @@ -1794,11 +1798,13 @@ export default class Crunchy implements ServiceClass { if (!decryptAudio.isOk) { console.error(decryptAudio.err); console.error(`Decryption failed with exit code ${decryptAudio.err.code}`); + fs.renameSync(`${tempTsFile}.audio.enc.m4s`, `${tsFile}.audio.enc.m4s`); return undefined; } else { if (!options.nocleanup) { - fs.removeSync(`${tsFile}.audio.enc.m4s`); + fs.removeSync(`${tempTsFile}.audio.enc.m4s`); } + fs.renameSync(`${tempTsFile}.audio.m4s`, `${tsFile}.audio.m4s`); files.push({ type: 'Audio', path: `${tsFile}.audio.m4s`, diff --git a/hidive.ts b/hidive.ts index 6532dce..fcbe177 100644 --- a/hidive.ts +++ b/hidive.ts @@ -1251,6 +1251,8 @@ export default class Hidive implements ServiceClass { const mathMsg = `(${mathParts}*${options.partsize})`; console.info('Total parts in video stream:', totalParts, mathMsg); const tsFile = path.isAbsolute(fileName) ? fileName : path.join(this.cfg.dir.content, fileName); + const tempFile = parseFileName(`temp-${selectedEpisode.id}`, variables, options.numbers, options.override).join(path.sep); + const tempTsFile = path.isAbsolute(tempFile as string) ? tempFile : path.join(this.cfg.dir.content, tempFile); const split = fileName.split(path.sep).slice(0, -1); split.forEach((val, ind, arr) => { const isAbsolut = path.isAbsolute(fileName); @@ -1261,7 +1263,7 @@ export default class Hidive implements ServiceClass { segments: chosenVideoSegments.segments }; const videoDownload = await new streamdl({ - output: `${tsFile}.video.enc.m4s`, + output: `${tempTsFile}.video.enc.m4s`, timeout: options.timeout, m3u8json: videoJson, // baseurl: chunkPlaylist.baseUrl, @@ -1290,19 +1292,21 @@ export default class Hidive implements ServiceClass { } if (this.cfg.bin.mp4decrypt) { const commandBase = `--show-progress --key ${encryptionKeys[1].kid}:${encryptionKeys[1].key} `; - const commandVideo = commandBase+`"${tsFile}.video.enc.m4s" "${tsFile}.video.m4s"`; + const commandVideo = commandBase+`"${tempTsFile}.video.enc.m4s" "${tempTsFile}.video.m4s"`; console.info('Started decrypting video'); const decryptVideo = exec('mp4decrypt', `"${this.cfg.bin.mp4decrypt}"`, commandVideo); if (!decryptVideo.isOk) { console.error(decryptVideo.err); console.error(`Decryption failed with exit code ${decryptVideo.err.code}`); + fs.renameSync(`${tempTsFile}.video.enc.m4s`, `${tsFile}.video.enc.m4s`); return undefined; } else { console.info('Decryption done for video'); if (!options.nocleanup) { - fs.removeSync(`${tsFile}.video.enc.m4s`); + fs.removeSync(`${tempTsFile}.video.enc.m4s`); } + fs.renameSync(`${tempTsFile}.video.m4s`, `${tsFile}.video.m4s`); files.push({ type: 'Video', path: `${tsFile}.video.m4s`, @@ -1327,6 +1331,8 @@ export default class Hidive implements ServiceClass { const mathParts = Math.ceil(totalParts / options.partsize); const mathMsg = `(${mathParts}*${options.partsize})`; console.info('Total parts in audio stream:', totalParts, mathMsg); + const tempFile = parseFileName(`temp-${selectedEpisode.id}.${chosenAudioSegments.language.name}`, variables, options.numbers, options.override).join(path.sep); + const tempTsFile = path.isAbsolute(tempFile as string) ? tempFile : path.join(this.cfg.dir.content, tempFile); const outFile = parseFileName(options.fileName + '.' + (chosenAudioSegments.language.name), variables, options.numbers, options.override).join(path.sep); const tsFile = path.isAbsolute(outFile as string) ? outFile : path.join(this.cfg.dir.content, outFile); const split = outFile.split(path.sep).slice(0, -1); @@ -1339,7 +1345,7 @@ export default class Hidive implements ServiceClass { segments: chosenAudioSegments.segments }; const audioDownload = await new streamdl({ - output: `${tsFile}.audio.enc.m4s`, + output: `${tempTsFile}.audio.enc.m4s`, timeout: options.timeout, m3u8json: audioJson, // baseurl: chunkPlaylist.baseUrl, @@ -1368,18 +1374,20 @@ export default class Hidive implements ServiceClass { } if (this.cfg.bin.mp4decrypt) { const commandBase = `--show-progress --key ${encryptionKeys[1].kid}:${encryptionKeys[1].key} `; - const commandAudio = commandBase+`"${tsFile}.audio.enc.m4s" "${tsFile}.audio.m4s"`; + const commandAudio = commandBase+`"${tempTsFile}.audio.enc.m4s" "${tempTsFile}.audio.m4s"`; console.info('Started decrypting audio'); const decryptAudio = exec('mp4decrypt', `"${this.cfg.bin.mp4decrypt}"`, commandAudio); if (!decryptAudio.isOk) { console.error(decryptAudio.err); console.error(`Decryption failed with exit code ${decryptAudio.err.code}`); + fs.renameSync(`${tempTsFile}.audio.enc.m4s`, `${tsFile}.audio.enc.m4s`); return undefined; } else { if (!options.nocleanup) { - fs.removeSync(`${tsFile}.audio.enc.m4s`); + fs.removeSync(`${tempTsFile}.audio.enc.m4s`); } + fs.renameSync(`${tempTsFile}.audio.m4s`, `${tsFile}.audio.m4s`); files.push({ type: 'Audio', path: `${tsFile}.audio.m4s`, @@ -1585,8 +1593,8 @@ export default class Hidive implements ServiceClass { console.info(`Selected quality: ${Object.keys(plSelectedList).find(a => plSelectedList[a] === selPlUrl)} @ ${plSelectedServer}`); console.info('Stream URL:', selPlUrl); // TODO check filename - const outFile = parseFileName(options.fileName + '.' + lang.name + '.' + videoIndex, variables, options.numbers, options.override).join(path.sep); fileName = parseFileName(options.fileName, variables, options.numbers, options.override).join(path.sep); + const outFile = parseFileName(options.fileName + '.' + lang.name + '.' + videoIndex, variables, options.numbers, options.override).join(path.sep); console.info(`Output filename: ${outFile}`); const chunkPage = await this.req.getData(selPlUrl); if(!chunkPage.ok || !chunkPage.res){