mp4decrypt -> shaka, jsencrypt -> node-forge, package update
This commit is contained in:
parent
f5403038e6
commit
1902f58f37
8
.gitignore
vendored
8
.gitignore
vendored
@ -20,11 +20,11 @@ build/
|
||||
crunchyroll-downloader-output-*/
|
||||
|
||||
# FFMPEG
|
||||
ffmpeg/ffmpeg.exe
|
||||
ffmpeg/ffprobe.exe
|
||||
ffmpeg/*
|
||||
ffmpeg/!.gitkeep
|
||||
|
||||
# MP4DECRYPT
|
||||
mp4decrypt/mp4decrypt.exe
|
||||
# SHAKA
|
||||
shaka/shaka.exe
|
||||
|
||||
# Keys
|
||||
keys/client
|
||||
|
3
app.config.ts
Normal file
3
app.config.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export default defineAppConfig({
|
||||
nuxtIcon: {},
|
||||
});
|
@ -244,7 +244,7 @@ export interface CrunchyEpisodeFetch {
|
||||
data: Array<{
|
||||
id: string
|
||||
episode_metadata: {
|
||||
series_id: string,
|
||||
series_id: string
|
||||
season_id: string
|
||||
}
|
||||
}>
|
||||
|
@ -31,7 +31,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import packageJson from '../package.json';
|
||||
import packageJson from '../package.json'
|
||||
|
||||
const isProduction = process.env.NODE_ENV !== 'development'
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
<template>
|
||||
<div class="relative flex flex-col items-center justify-center h-full" style="-webkit-app-region: no-drag">
|
||||
<img src="/logo.png" class="h-24" />
|
||||
<div class="text-base text-center leading-[18px]">
|
||||
CrunchyDL
|
||||
</div>
|
||||
<div class="text-base text-center leading-[18px]"> CrunchyDL </div>
|
||||
<div class="text-sm mt-1 text-gray-200"> v{{ packageJson.version }} </div>
|
||||
<div class="absolute right-0 bottom-0 text-xs text-gray-200"> Made by OpenSTDL </div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import packageJson from '../../package.json';
|
||||
import packageJson from '../../package.json'
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -1,15 +1,10 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
|
||||
export default defineNuxtConfig({
|
||||
typescript: {
|
||||
shim: false
|
||||
},
|
||||
ssr: false,
|
||||
modules: ['@nuxtjs/tailwindcss', 'nuxt-icon', '@nuxtjs/google-fonts'],
|
||||
googleFonts: {
|
||||
families: {
|
||||
'DM+Sans': ['600', '1000'],
|
||||
'Protest+Riot': true
|
||||
ssr: false,
|
||||
modules: ['@nuxtjs/tailwindcss', 'nuxt-icon', '@nuxtjs/google-fonts'],
|
||||
googleFonts: {
|
||||
families: {
|
||||
'DM+Sans': ['600', '1000'],
|
||||
'Protest+Riot': true
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
23
package.json
23
package.json
@ -8,13 +8,13 @@
|
||||
"repository": "https://github.com/OpenSTDL/CrunchyDL",
|
||||
"scripts": {
|
||||
"dev": "nuxt dev -o",
|
||||
"build": "nuxt generate",
|
||||
"build": "nuxt build",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare && electron-builder install-app-deps",
|
||||
"transpile-src": "tsc -p ./src --outDir .output/src",
|
||||
"dev:electron": "NODE_ENV=development concurrently --kill-others \"nuxt dev\" \"tsc-watch -p ./src --outDir .output/src --onSuccess 'electron ./.output/src/electron/background.js'\"",
|
||||
"dev:electron:win": "set NODE_ENV=development& concurrently --kill-others \"nuxt dev\" \"tsc-watch -p ./src --outDir .output/src --onSuccess run.electron\"",
|
||||
"build:electron": "pnpm prettier:fix && pnpm build && pnpm transpile-src && node build.js",
|
||||
"build:electron": "pnpm prettier:fix && nuxt generate && pnpm transpile-src && node build.js",
|
||||
"prettier:fix": "pnpm prettier src --write && pnpm prettier components --write && pnpm prettier pages --write && pnpm prettier build.js --write"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -27,6 +27,7 @@
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/fluent-ffmpeg": "^2.1.24",
|
||||
"@types/node-cron": "^3.0.11",
|
||||
"@types/node-forge": "^1.3.11",
|
||||
"concurrently": "^8.2.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"electron": "^30.1.2",
|
||||
@ -34,18 +35,15 @@
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^8.10.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"long": "^5.2.3",
|
||||
"modclean": "3.0.0-beta.1",
|
||||
"nuxt": "3.11.2",
|
||||
"nuxt-icon": "^0.6.10",
|
||||
"prettier": "^2.8.8",
|
||||
"protobufjs": "^7.3.2",
|
||||
"sass": "^1.77.6",
|
||||
"sass-loader": "^13.3.3",
|
||||
"tsc-watch": "^6.2.0",
|
||||
"typescript": "^5.5.2",
|
||||
"wait-on": "^7.2.0",
|
||||
"winston": "^3.13.0"
|
||||
"typescript": "5.4.4",
|
||||
"wait-on": "^7.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^9.0.1",
|
||||
@ -58,18 +56,21 @@
|
||||
"express": "^4.19.2",
|
||||
"fastify": "^4.28.0",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"long": "^5.2.3",
|
||||
"mpd-parser": "^1.3.0",
|
||||
"node-cache": "^5.1.2",
|
||||
"node-cron": "^3.0.3",
|
||||
"node-forge": "^1.3.1",
|
||||
"protobufjs": "^7.3.2",
|
||||
"sequelize": "^6.37.3",
|
||||
"sqlite3": "5.1.6"
|
||||
"sqlite3": "5.1.6",
|
||||
"winston": "^3.13.0"
|
||||
},
|
||||
"build": {
|
||||
"files": [
|
||||
"!**/pages/*",
|
||||
"!**/ffmpeg/*",
|
||||
"!**/mp4decrypt/*",
|
||||
"!**/shaka/*",
|
||||
"!**/.git/*",
|
||||
"!**/.github/*",
|
||||
"!**/.nuxt/*",
|
||||
@ -77,7 +78,7 @@
|
||||
],
|
||||
"extraResources": [
|
||||
"./ffmpeg/**",
|
||||
"./mp4decrypt/**"
|
||||
"./shaka/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -234,7 +234,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="service === 'crunchyroll'" class="relative flex flex-col select-none">
|
||||
<div @click="selectHardSub ? (selectHardSub = false) : (selectHardSub = true)" class="bg-[#5c5b5b] focus:outline-none px-3 py-2 rounded-xl text-sm text-center cursor-pointer">
|
||||
<div
|
||||
@click="selectHardSub ? (selectHardSub = false) : (selectHardSub = true)"
|
||||
class="bg-[#5c5b5b] focus:outline-none px-3 py-2 rounded-xl text-sm text-center cursor-pointer"
|
||||
>
|
||||
Hardsub:
|
||||
{{ selectedHardSub ? `${selectedHardSub.name} (${selectedHardSub.format})` : 'No Hardsub selected' }}
|
||||
</div>
|
||||
@ -247,7 +250,7 @@
|
||||
class="flex flex-row items-center justify-center gap-3 py-2 rounded-xl text-sm"
|
||||
:class="selectedHardSub && selectedHardSub.locale === l.locale && selectedHardSub.format === 'sub' ? 'bg-[#585858]' : 'hover:bg-[#747474]'"
|
||||
>
|
||||
{{ l.name }}<br>(sub)
|
||||
{{ l.name }}<br />(sub)
|
||||
</button>
|
||||
<button
|
||||
v-for="l in CRselectedShow?.Dubs.map((s) => {
|
||||
@ -257,7 +260,7 @@
|
||||
class="flex flex-row items-center justify-center gap-3 py-2 rounded-xl text-sm"
|
||||
:class="selectedHardSub && selectedHardSub.locale === l.locale && selectedHardSub.format === 'dub' ? 'bg-[#585858]' : 'hover:bg-[#747474]'"
|
||||
>
|
||||
{{ l.name }}<br>(dub)
|
||||
{{ l.name }}<br />(dub)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -429,7 +432,7 @@ const selectSub = ref<boolean>(false)
|
||||
const selectedSubs = ref<Array<{ name: string | undefined; locale: string }>>([])
|
||||
|
||||
const selectHardSub = ref<boolean>(false)
|
||||
const selectedHardSub = ref<{ name: string | undefined; locale: string, format: string }>()
|
||||
const selectedHardSub = ref<{ name: string | undefined; locale: string; format: string }>()
|
||||
|
||||
const tab = ref<number>(1)
|
||||
const search = ref<string>('')
|
||||
@ -779,7 +782,7 @@ const switchToSeason = async () => {
|
||||
|
||||
if (url.value && url.value.includes('crunchyroll') && url.value.includes('/watch/') && !CRselectedShow.value) {
|
||||
var episodeID: string | string[] = url.value.split('/')
|
||||
episodeID = episodeID[episodeID.length-2]
|
||||
episodeID = episodeID[episodeID.length - 2]
|
||||
const seriesID = await getCREpisodeSeriesID(episodeID)
|
||||
if (!seriesID) {
|
||||
alert('Episode not found')
|
||||
@ -798,7 +801,7 @@ const switchToSeason = async () => {
|
||||
isFetchingSeasons.value--
|
||||
return
|
||||
}
|
||||
selectedSeason.value = seasons.value.find(s => s.id === seriesID.season) ?? seasons.value[0]
|
||||
selectedSeason.value = seasons.value.find((s) => s.id === seriesID.season) ?? seasons.value[0]
|
||||
episodes.value = await listEpisodeCrunchy(selectedSeason.value.id, CRselectedShow.value.Geo)
|
||||
if (episodes.value) {
|
||||
selectedStartEpisode.value = episodes.value[0]
|
||||
|
@ -127,7 +127,7 @@
|
||||
</div>
|
||||
<div class="relative flex flex-row gap-2 h-full items-end">
|
||||
<div class="text-xs">{{ p.quality }}p</div>
|
||||
<div v-if="p.qualityaudio" class="text-xs">{{ audioQualities[p.qualityaudio-1] ?? '44.10 kHz' }}</div>
|
||||
<div v-if="p.qualityaudio" class="text-xs">{{ audioQualities[p.qualityaudio - 1] ?? '44.10 kHz' }}</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">Subs: {{ p.sub.length !== 0 ? p.sub.map((t) => t.name).join(', ') : '-' }}</div>
|
||||
@ -166,7 +166,7 @@ const playlist = ref<
|
||||
media: CrunchyEpisode | ADNEpisode
|
||||
dub: Array<{ locale: string; name: string }>
|
||||
sub: Array<{ locale: string; name: string }>
|
||||
hardsub: { name: string | undefined; locale: string, format: string }
|
||||
hardsub: { name: string | undefined; locale: string; format: string }
|
||||
dir: string
|
||||
installDir: string
|
||||
partsleft: number
|
||||
@ -194,7 +194,7 @@ const getPlaylist = async () => {
|
||||
media: CrunchyEpisode | ADNEpisode
|
||||
dub: Array<{ locale: string; name: string }>
|
||||
sub: Array<{ locale: string; name: string }>
|
||||
hardsub: { name: string | undefined; locale: string, format: string }
|
||||
hardsub: { name: string | undefined; locale: string; format: string }
|
||||
dir: string
|
||||
installDir: string
|
||||
partsleft: number
|
||||
|
918
pnpm-lock.yaml
918
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -46,7 +46,7 @@ interface PlaylistAttributes {
|
||||
media: CrunchyEpisode | ADNEpisode
|
||||
dub: { name: string | undefined; locale: string }[]
|
||||
sub: { name: string | undefined; locale: string }[]
|
||||
hardsub: { name: string | undefined; locale: string, format: string }
|
||||
hardsub: { name: string | undefined; locale: string; format: string }
|
||||
quality: 1080 | 720 | 480 | 360 | 240
|
||||
qualityaudio: 1 | 2 | 3 | undefined
|
||||
dir: string
|
||||
@ -60,7 +60,7 @@ interface PlaylistCreateAttributes {
|
||||
media: CrunchyEpisode | ADNEpisode
|
||||
dub: { name: string | undefined; locale: string }[]
|
||||
sub: { name: string | undefined; locale: string }[]
|
||||
hardsub: { name: string | undefined; locale: string, format: string } | undefined
|
||||
hardsub: { name: string | undefined; locale: string; format: string } | undefined
|
||||
dir: string
|
||||
quality: 1080 | 720 | 480 | 360 | 240
|
||||
qualityaudio: 1 | 2 | 3 | undefined
|
||||
|
@ -1,11 +1,10 @@
|
||||
import JSEncrypt from 'jsencrypt'
|
||||
import CryptoJS from 'crypto-js'
|
||||
import { server } from '../../api'
|
||||
import { ADNLink, ADNPlayerConfig } from '../../types/adn'
|
||||
import { messageBox } from '../../../electron/background'
|
||||
import { useFetch } from '../useFetch'
|
||||
import { loggedInCheck } from '../service/service.service'
|
||||
import { parse as mpdParse, parse } from 'mpd-parser'
|
||||
import * as forge from 'node-forge'
|
||||
|
||||
export async function adnLogin(user: string, passw: string) {
|
||||
const cachedData:
|
||||
@ -178,12 +177,9 @@ async function getPlayerEncryptedToken(id: number, geo: 'de' | 'fr') {
|
||||
|
||||
if (!token) return
|
||||
|
||||
var key = new JSEncrypt()
|
||||
var random = randomHexaString(16)
|
||||
const publicKeyPem = `-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbQrCJBRmaXM4gJidDmcpWDssgnumHinCLHAgS4buMtdH7dEGGEUfBofLzoEdt1jqcrCDT6YNhM0aFCqbLOPFtx9cg/X2G/G5bPVu8cuFM0L+ehp8s6izK1kjx3OOPH/kWzvstM5tkqgJkNyNEvHdeJl6KhS+IFEqwvZqgbBpKuwIDAQAB-----END PUBLIC KEY-----`
|
||||
|
||||
key.setPublicKey(
|
||||
'-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbQrCJBRmaXM4gJidDmcpWDssgnumHinCLHAgS4buMtdH7dEGGEUfBofLzoEdt1jqcrCDT6YNhM0aFCqbLOPFtx9cg/X2G/G5bPVu8cuFM0L+ehp8s6izK1kjx3OOPH/kWzvstM5tkqgJkNyNEvHdeJl6KhS+IFEqwvZqgbBpKuwIDAQAB-----END PUBLIC KEY-----'
|
||||
)
|
||||
var random = CryptoJS.lib.WordArray.random(16).toString(CryptoJS.enc.Hex)
|
||||
|
||||
const data = {
|
||||
k: random,
|
||||
@ -192,11 +188,19 @@ async function getPlayerEncryptedToken(id: number, geo: 'de' | 'fr') {
|
||||
|
||||
const finisheddata = JSON.stringify(data)
|
||||
|
||||
const encryptedData = key.encrypt(finisheddata) || ''
|
||||
const encryptedData = encryptWithPublicKey(publicKeyPem, finisheddata)
|
||||
|
||||
return { data: encryptedData, random: random }
|
||||
}
|
||||
|
||||
function encryptWithPublicKey(publicKeyPem: string, data: string) {
|
||||
const publicKey = forge.pki.publicKeyFromPem(publicKeyPem)
|
||||
const encryptedData = publicKey.encrypt(data, 'RSA-OAEP', {
|
||||
md: forge.md.sha256.create()
|
||||
})
|
||||
return forge.util.encode64(encryptedData)
|
||||
}
|
||||
|
||||
export async function adnGetPlaylist(animeid: number, geo: 'de' | 'fr') {
|
||||
const token = await getPlayerEncryptedToken(animeid, geo)
|
||||
|
||||
|
@ -98,7 +98,7 @@ export async function addPlaylistController(
|
||||
episodes: CrunchyEpisodes
|
||||
dubs: { name: string | undefined; locale: string }[]
|
||||
subs: { name: string | undefined; locale: string }[]
|
||||
hardsub: { name: string | undefined; locale: string, format: string } | undefined
|
||||
hardsub: { name: string | undefined; locale: string; format: string } | undefined
|
||||
dir: string
|
||||
quality: 1080 | 720 | 480 | 360 | 240
|
||||
qualityaudio: 1 | 2 | 3 | undefined
|
||||
|
@ -15,9 +15,9 @@ import { ADNEpisode } from '../../types/adn'
|
||||
import { messageBox } from '../../../electron/background'
|
||||
import { getFFMPEGPath } from '../../services/ffmpeg'
|
||||
import { getDRMKeys, Uint8ArrayToBase64 } from '../../services/decryption'
|
||||
import { getMP4DecryptPath } from '../../services/mp4decrypt'
|
||||
import { getShakaPath } from '../../services/shaka'
|
||||
const ffmpegP = getFFMPEGPath()
|
||||
const mp4e = getMP4DecryptPath()
|
||||
const shaka = getShakaPath()
|
||||
import util from 'util'
|
||||
import settings from 'electron-settings'
|
||||
import { server } from '../../api'
|
||||
@ -211,7 +211,7 @@ export async function addEpisodeToPlaylist(
|
||||
e: CrunchyEpisode,
|
||||
s: { name: string | undefined; locale: string }[],
|
||||
d: { name: string | undefined; locale: string }[],
|
||||
hardsub: { name: string | undefined; locale: string, format: string } | undefined,
|
||||
hardsub: { name: string | undefined; locale: string; format: string } | undefined,
|
||||
dir: string,
|
||||
status:
|
||||
| 'waiting'
|
||||
@ -471,7 +471,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
e: string,
|
||||
dubs: Array<string>,
|
||||
subs: Array<string>,
|
||||
hardsub: { name: string | undefined; locale: string; format: string; },
|
||||
hardsub: { name: string | undefined; locale: string; format: string },
|
||||
episodeID: string,
|
||||
downloadID: number,
|
||||
name: string,
|
||||
@ -792,7 +792,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
let p: { filename: string; url: string }[] = []
|
||||
|
||||
if (playlist.mediaGroups.AUDIO.audio.main.playlists[playlistindex].contentProtection) {
|
||||
if (!playlist.mediaGroups.AUDIO.audio.main.playlists[playlistindex].contentProtection['com.widevine.alpha'].pssh) {
|
||||
if (!playlist.mediaGroups.AUDIO.audio.main.playlists![playlistindex]!.contentProtection!['com.widevine.alpha']!.pssh) {
|
||||
console.log('No PSSH found, exiting.')
|
||||
messageBox(
|
||||
'error',
|
||||
@ -811,7 +811,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
})
|
||||
return
|
||||
}
|
||||
pssh = Uint8ArrayToBase64(playlist.mediaGroups.AUDIO.audio.main.playlists[playlistindex].contentProtection['com.widevine.alpha'].pssh)
|
||||
pssh = Uint8ArrayToBase64(playlist.mediaGroups.AUDIO.audio.main.playlists![playlistindex]!.contentProtection!['com.widevine.alpha'].pssh!)
|
||||
|
||||
keys = await getDRMKeys(pssh, assetId[1], list.account_id)
|
||||
|
||||
@ -946,9 +946,9 @@ export async function downloadCrunchyrollPlaylist(
|
||||
var downloadGEO
|
||||
|
||||
if (hardsub && hardsub.locale) {
|
||||
var hardsubURL: string | undefined;
|
||||
var hardsubURL: string | undefined
|
||||
|
||||
var hardsubGEO: string | undefined;;
|
||||
var hardsubGEO: string | undefined
|
||||
|
||||
if (hardsub.format === 'dub') {
|
||||
const found = play.data.versions.find((h) => h.audio_locale === hardsub.locale)
|
||||
@ -989,7 +989,14 @@ export async function downloadCrunchyrollPlaylist(
|
||||
downloadURL = play.data.url
|
||||
downloadGEO = play.data.geo
|
||||
console.log('Hardsub Playlist not found')
|
||||
messageBox('warning', ['Cancel'], 2, 'Hardsub Playlist not found', 'Hardsub Playlist not found', `${hardsub.locale} Hardsub Playlist not found, downloading japanese playlist instead.`)
|
||||
messageBox(
|
||||
'warning',
|
||||
['Cancel'],
|
||||
2,
|
||||
'Hardsub Playlist not found',
|
||||
'Hardsub Playlist not found',
|
||||
`${hardsub.locale} Hardsub Playlist not found, downloading japanese playlist instead.`
|
||||
)
|
||||
server.logger.log({
|
||||
level: 'error',
|
||||
message: `${hardsub.locale} Hardsub Playlist not found, downloading japanese playlist instead.`,
|
||||
@ -1296,11 +1303,8 @@ async function mergeParts(parts: { filename: string; url: string }[], downloadID
|
||||
|
||||
await updatePlaylistByID(downloadID, 'decrypting video')
|
||||
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 command = `${shaka} input="${tmp}/temp-main.m4s",stream=video,output="${tmp}/main.m4s" --enable_raw_key_decryption --keys key_id=${drmkeys[1].kid}:key=${drmkeys[1].key}`
|
||||
|
||||
await exec(command)
|
||||
console.log('Video Decryption finished')
|
||||
@ -1397,15 +1401,13 @@ async function mergeVideoFile(
|
||||
if (format === 'mp4') {
|
||||
options.push('-c:s mov_text')
|
||||
}
|
||||
|
||||
|
||||
for (const [index, a] of audios.entries()) {
|
||||
output.addInput(a)
|
||||
options.push(`-map ${ffindex}:a:0`)
|
||||
options.push(
|
||||
`-metadata:s:a:${index} language=${
|
||||
locales.find((l) => l.locale === getFilename(a, '.aac', '/'))
|
||||
? locales.find((l) => l.locale === getFilename(a, '.aac', '/'))?.iso
|
||||
: getFilename(a, '.aac', '/')
|
||||
locales.find((l) => l.locale === getFilename(a, '.aac', '/')) ? locales.find((l) => l.locale === getFilename(a, '.aac', '/'))?.iso : getFilename(a, '.aac', '/')
|
||||
}`
|
||||
)
|
||||
options.push(
|
||||
@ -1415,7 +1417,7 @@ async function mergeVideoFile(
|
||||
: getFilename(a, '.aac', '/')
|
||||
}`
|
||||
)
|
||||
|
||||
|
||||
ffindex++
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@ import { checkFileExistence, createFolder, deleteFolder } from './folder'
|
||||
import { concatenateTSFiles } from './concatenate'
|
||||
import Ffmpeg from 'fluent-ffmpeg'
|
||||
import { getFFMPEGPath } from './ffmpeg'
|
||||
import { getMP4DecryptPath } from '../services/mp4decrypt'
|
||||
import { getShakaPath } from './shaka'
|
||||
const ffmpegP = getFFMPEGPath()
|
||||
const mp4e = getMP4DecryptPath()
|
||||
const shaka = getShakaPath()
|
||||
import util from 'util'
|
||||
import { server } from '../api'
|
||||
const exec = util.promisify(require('child_process').exec)
|
||||
@ -161,11 +161,8 @@ async function mergePartsAudio(
|
||||
dn.status = 'decrypting'
|
||||
}
|
||||
console.log(`Audio 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 command = `${shaka} input="${tmp}/temp-main.m4s",stream=audio,output="${tmp}/main.m4s" --enable_raw_key_decryption --keys key_id=${drmkeys[1].kid}:key=${drmkeys[1].key}`
|
||||
|
||||
await exec(command)
|
||||
concatenatedFile = `${tmp}/main.m4s`
|
||||
|
@ -105,8 +105,8 @@ export function getFilename(path: string, ext: string, delimiter: string) {
|
||||
const segments = path.split(delimiter)
|
||||
|
||||
if (segments.length == 0) {
|
||||
return "unkown"
|
||||
return 'unkown'
|
||||
}
|
||||
|
||||
return segments[segments.length - 1].split(ext)[0]
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
import { app } from 'electron'
|
||||
import path from 'path'
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
const appPath = app.getAppPath()
|
||||
const resourcesPath = path.dirname(appPath)
|
||||
const decryptPath = path.join(resourcesPath, 'mp4decrypt')
|
||||
if (isDev) {
|
||||
require('dotenv').config()
|
||||
}
|
||||
|
||||
export function getMP4DecryptPath() {
|
||||
if (isDev) {
|
||||
const mp4Decrypt = process.env.MP4DECRYPT_PATH
|
||||
|
||||
return mp4Decrypt
|
||||
} else {
|
||||
const mp4Decrypt = `"${path.join(decryptPath, 'mp4decrypt.exe')}"`
|
||||
|
||||
return mp4Decrypt
|
||||
}
|
||||
}
|
21
src/api/services/shaka.ts
Normal file
21
src/api/services/shaka.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { app } from 'electron'
|
||||
import path from 'path'
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
const appPath = app.getAppPath()
|
||||
const resourcesPath = path.dirname(appPath)
|
||||
const shakaFolderPath = path.join(resourcesPath, 'shaka')
|
||||
if (isDev) {
|
||||
require('dotenv').config()
|
||||
}
|
||||
|
||||
export function getShakaPath() {
|
||||
if (isDev) {
|
||||
const shaka = process.env.SHAKA_PATH
|
||||
|
||||
return shaka
|
||||
} else {
|
||||
const shaka = `"${path.join(shakaFolderPath, 'shaka.exe')}"`
|
||||
|
||||
return shaka
|
||||
}
|
||||
}
|
@ -17,7 +17,6 @@ export async function downloadCRSub(
|
||||
qual: 1080 | 720 | 480 | 360 | 240
|
||||
) {
|
||||
try {
|
||||
|
||||
var resamplerActive = await settings.get('subtitleResamplerActive')
|
||||
|
||||
if (resamplerActive === undefined || resamplerActive === null) {
|
||||
@ -59,8 +58,8 @@ export async function downloadCRSub(
|
||||
|
||||
await finished(readableStream.pipe(stream))
|
||||
console.log(`Sub ${sub.language}.${sub.format} downloaded`)
|
||||
|
||||
return path
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
var parsedASS = parse(await response.text())
|
||||
|
@ -1,23 +1,15 @@
|
||||
// This is the dynamic renderer script for Electron.
|
||||
// You can implement your custom renderer process configuration etc. here!
|
||||
// --------------------------------------------
|
||||
import * as path from 'path'
|
||||
import { BrowserWindow } from 'electron'
|
||||
import express, { static as serveStatic } from 'express'
|
||||
|
||||
// Internals
|
||||
// =========
|
||||
const isProduction = process.env.NODE_ENV !== 'development'
|
||||
|
||||
// Dynamic Renderer
|
||||
// ================
|
||||
export default async function (mainWindow: BrowserWindow) {
|
||||
if (!isProduction) return mainWindow.loadURL('http://localhost:3000/')
|
||||
const app = express()
|
||||
app.use('/', serveStatic(path.join(__dirname, '../../public')))
|
||||
const listener = app.listen(8079, 'localhost', () => {
|
||||
const port = (listener.address() as any).port
|
||||
console.log('Dynamic-Renderer Listening on', port)
|
||||
mainWindow.loadURL(`http://localhost:${port}`)
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user