added
This commit is contained in:
parent
03bc1d5270
commit
755b69daf1
7
.gitignore
vendored
7
.gitignore
vendored
@ -10,18 +10,19 @@ dist
|
||||
.DS_Store
|
||||
|
||||
# Electron
|
||||
crunchyroll-downloader-advanced-output
|
||||
crunchyroll-downloader-output
|
||||
debug.log
|
||||
debug.log
|
||||
*.log
|
||||
debug.json
|
||||
errors.json
|
||||
build/
|
||||
crunchyroll-downloader-advanced-output-*/
|
||||
crunchyroll-downloader-output-*/
|
||||
updater/
|
||||
|
||||
# FFMPEG
|
||||
ffmpeg/
|
||||
|
||||
# MP4DECRYPT
|
||||
mp4decrypt/
|
||||
keys/
|
||||
src/api/services/widevine.ts
|
||||
|
13
build.js
13
build.js
@ -6,8 +6,8 @@ const Platform = builder.Platform
|
||||
* @type {import('electron-builder').Configuration}
|
||||
*/
|
||||
const options = {
|
||||
appId: 'com.stratum.crunchyrolldownloaderadvanced',
|
||||
productName: 'Crunchyroll Downloader Advanced',
|
||||
appId: 'com.stratum.crunchyrolldownloader',
|
||||
productName: 'Crunchyroll Downloader',
|
||||
|
||||
compression: 'maximum',
|
||||
removePackageScripts: true,
|
||||
@ -15,12 +15,17 @@ const options = {
|
||||
nodeGypRebuild: true,
|
||||
buildDependenciesFromSource: true,
|
||||
|
||||
publish: {
|
||||
provider: 'github',
|
||||
releaseType: 'release'
|
||||
},
|
||||
|
||||
directories: {
|
||||
output: 'crunchyroll-downloader-advanced-output-${version}'
|
||||
output: 'crunchyroll-downloader-output-${version}'
|
||||
},
|
||||
|
||||
win: {
|
||||
artifactName: 'crunchyroll-downloader-advanced-${version}-windows-installer.${ext}',
|
||||
artifactName: 'crunchyroll-downloader-${version}-windows-installer.${ext}',
|
||||
icon: 'public/favicon.ico',
|
||||
target: [
|
||||
{
|
||||
|
@ -14,8 +14,7 @@
|
||||
<img src="/logo.png" class="h-8" />
|
||||
<div class="text-[10px] leading-[10px] text-opacity-90 text-white select-none"
|
||||
>Crunchyroll <br />
|
||||
Downloader <br />
|
||||
Advanced</div
|
||||
Downloader</div
|
||||
>
|
||||
</div>
|
||||
<div class="w-full flex gap-2 flex-row items-center justify-center">
|
||||
|
58
components/Updater.vue
Normal file
58
components/Updater.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<div
|
||||
class="fixed bottom-3 right-5 p-3 flex flex-col bg-[#111111dc] w-80 min-h-24 rounded-xl font-dm text-white transition-all duration-300"
|
||||
:class="
|
||||
(data?.status === 'update-available' && !ignoreUpdate) || data?.status === 'downloading' || data?.status === 'update-downloaded'
|
||||
? 'opacity-100'
|
||||
: 'opacity-0 pointer-events-none'
|
||||
"
|
||||
>
|
||||
<button @click="ignoreUpdate = true" class="absolute right-3 top-2">
|
||||
<Icon name="akar-icons:cross" class="h-4 w-4 text-white" />
|
||||
</button>
|
||||
<div class="text-base text-center"> Update available </div>
|
||||
<div class="text-sm text-center"> A new update is available </div>
|
||||
<div v-if="data && data.info && data.info.version" class="text-sm text-center"> v{{ data.info.version }} </div>
|
||||
<button @click="startDownload" v-if="data && data.status === 'update-available'" class="text-sm py-3 bg-[#363434] mt-5 rounded-xl" :disabled="downloading">
|
||||
Download Update
|
||||
</button>
|
||||
<button v-if="data && data.status === 'downloading'" class="relative text-sm py-3 bg-[#363434] mt-5 rounded-xl overflow-hidden">
|
||||
<div class="absolute top-0 left-0 w-full h-full bg-[#a1a1a141] transition-all duration-300" :style="`width: calc((${data.info.percent} / 100) * 100%);`"></div>
|
||||
Downloading...
|
||||
</button>
|
||||
<button @click="startInstall" v-if="data && data.status === 'update-downloaded'" class="text-sm py-3 bg-[#363434] mt-5 rounded-xl" :disabled="installing">
|
||||
Install Update
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const data = ref<{ status: string; info: any }>()
|
||||
const downloading = ref<boolean>(false)
|
||||
const installing = ref<boolean>(false)
|
||||
const ignoreUpdate = ref<boolean>(false)
|
||||
|
||||
const checkUpdate = () => {
|
||||
;(window as any).myAPI.getUpdateStatus().then((result: any) => {
|
||||
data.value = result
|
||||
})
|
||||
}
|
||||
|
||||
const startDownload = () => {
|
||||
downloading.value = true
|
||||
;(window as any).myAPI.startUpdateDownload()
|
||||
}
|
||||
|
||||
const startInstall = () => {
|
||||
installing.value = true
|
||||
;(window as any).myAPI.startUpdateInstall()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkUpdate()
|
||||
|
||||
setInterval(checkUpdate, 2000)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style></style>
|
11
package.json
11
package.json
@ -1,10 +1,11 @@
|
||||
{
|
||||
"name": "crunchyroll-downloader-advanced",
|
||||
"name": "crunchyroll-downloader",
|
||||
"author": "Stratum",
|
||||
"description": "Crunchyroll Downloader Advanced",
|
||||
"version": "1.0.0",
|
||||
"description": "Crunchyroll Downloader",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"main": ".output/src/electron/background.js",
|
||||
"repository": "https://github.com/stratuma/Crunchyroll-Downloader-v4.0",
|
||||
"scripts": {
|
||||
"dev": "nuxt dev -o",
|
||||
"build": "nuxt generate",
|
||||
@ -53,11 +54,9 @@
|
||||
"fastify": "^4.26.2",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"long": "^5.2.3",
|
||||
"mpd-parser": "^1.3.0",
|
||||
"node-cache": "^5.1.2",
|
||||
"node-cron": "^3.0.3",
|
||||
"protobufjs": "^7.2.6",
|
||||
"sequelize": "^6.37.3",
|
||||
"sqlite3": "5.1.6"
|
||||
},
|
||||
@ -65,7 +64,7 @@
|
||||
"extraResources": [
|
||||
"./ffmpeg/**",
|
||||
"./mp4decrypt/**",
|
||||
"./keys/**"
|
||||
"./updater/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,9 @@ import { parse as mpdParse } from 'mpd-parser'
|
||||
import { loggedInCheck } from '../service/service.service'
|
||||
import { app } from 'electron'
|
||||
|
||||
// Disable when Crunchyroll turns off switch endpoint
|
||||
const enableDRMBypass = false
|
||||
|
||||
const crErrors = [
|
||||
{
|
||||
error: 'invalid_grant',
|
||||
@ -118,46 +121,15 @@ export async function crunchyGetPlaylist(q: string) {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://cr-play-service.prd.crunchyrollsvc.com/v1/${q}/console/switch/play`, {
|
||||
method: 'GET',
|
||||
headers: headers
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
const data: VideoPlaylist = JSON.parse(await response.text())
|
||||
|
||||
data.hardSubs = Object.values((data as any).hardSubs)
|
||||
|
||||
data.subtitles = Object.values((data as any).subtitles)
|
||||
|
||||
return { data: data, account_id: login.account_id }
|
||||
} else {
|
||||
throw new Error(await response.text())
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(e as string)
|
||||
}
|
||||
}
|
||||
|
||||
export async function crunchyGetPlaylistDRM(q: 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}`,
|
||||
'x-cr-stream-limits': 'false'
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://cr-play-service.prd.crunchyrollsvc.com/v1/${q}/tv/samsung/play`, {
|
||||
method: 'GET',
|
||||
headers: headers
|
||||
})
|
||||
const response = await fetch(
|
||||
enableDRMBypass
|
||||
? `https://cr-play-service.prd.crunchyrollsvc.com/v1/${q}/tv/samsung/play`
|
||||
: `https://cr-play-service.prd.crunchyrollsvc.com/v1/${q}/console/switch/play`,
|
||||
{
|
||||
method: 'GET',
|
||||
headers: headers
|
||||
}
|
||||
)
|
||||
|
||||
if (response.ok) {
|
||||
const data: VideoPlaylist = JSON.parse(await response.text())
|
||||
|
@ -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, deleteVideoToken } from '../crunchyroll/crunchyroll.service'
|
||||
import { crunchyGetPlaylist, crunchyGetPlaylistMPD, deleteVideoToken } from '../crunchyroll/crunchyroll.service'
|
||||
import fs from 'fs'
|
||||
var cron = require('node-cron')
|
||||
import { Readable } from 'stream'
|
||||
@ -327,7 +327,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
|
||||
await updatePlaylistByID(downloadID, 'downloading')
|
||||
|
||||
var playlist = await crunchyGetPlaylistDRM(e)
|
||||
var playlist = await crunchyGetPlaylist(e)
|
||||
|
||||
if (!playlist) {
|
||||
await updatePlaylistByID(downloadID, 'failed')
|
||||
@ -340,7 +340,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
const found = playlist.data.versions.find((v) => v.audio_locale === 'ja-JP')
|
||||
if (found) {
|
||||
await deleteVideoToken(episodeID, playlist.data.token)
|
||||
playlist = await crunchyGetPlaylistDRM(found.guid)
|
||||
playlist = await crunchyGetPlaylist(found.guid)
|
||||
} else {
|
||||
console.log('Exact Playlist not found, taking what crunchy gives.'),
|
||||
messageBox(
|
||||
@ -394,7 +394,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
if (playlist.data.audioLocale !== 'ja-JP') {
|
||||
const foundStream = playlist.data.versions.find((v) => v.audio_locale === 'ja-JP')
|
||||
if (foundStream) {
|
||||
subPlaylist = await crunchyGetPlaylistDRM(foundStream.guid)
|
||||
subPlaylist = await crunchyGetPlaylist(foundStream.guid)
|
||||
}
|
||||
} else {
|
||||
subPlaylist = playlist
|
||||
@ -424,7 +424,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
}
|
||||
|
||||
if (found) {
|
||||
const list = await crunchyGetPlaylistDRM(found.guid)
|
||||
const list = await crunchyGetPlaylist(found.guid)
|
||||
if (list) {
|
||||
const foundSub = list.data.subtitles.find((sub) => sub.language === d)
|
||||
if (foundSub) {
|
||||
@ -479,7 +479,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
const audioDownload = async () => {
|
||||
const audios: Array<string> = []
|
||||
for (const v of dubDownloadList) {
|
||||
const list = await crunchyGetPlaylistDRM(v.guid)
|
||||
const list = await crunchyGetPlaylist(v.guid)
|
||||
|
||||
if (!list) return
|
||||
|
||||
@ -554,7 +554,7 @@ export async function downloadCrunchyrollPlaylist(
|
||||
return
|
||||
}
|
||||
|
||||
const play = await crunchyGetPlaylistDRM(code)
|
||||
const play = await crunchyGetPlaylist(code)
|
||||
|
||||
if (!play) {
|
||||
await updatePlaylistByID(downloadID, 'failed')
|
||||
|
Reference in New Issue
Block a user