mirror of
https://github.com/OpenSTDL/CrunchyDL.git
synced 2024-10-18 14:25:06 +02:00
multiple fixes and additions
This commit is contained in:
parent
e97bb2a525
commit
7e255b6fcc
17
.vscode/launch.json
vendored
Normal file
17
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug Main Process",
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
|
||||||
|
"windows": {
|
||||||
|
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
|
||||||
|
},
|
||||||
|
"args" : ["."],
|
||||||
|
"outputCapture": "std"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -9,19 +9,13 @@
|
|||||||
placeholder="Episode Naming"
|
placeholder="Episode Naming"
|
||||||
class="bg-[#5c5b5b] w-full focus:outline-none px-3 py-2 rounded-xl text-sm text-center"
|
class="bg-[#5c5b5b] w-full focus:outline-none px-3 py-2 rounded-xl text-sm text-center"
|
||||||
/>
|
/>
|
||||||
<div class="text-sm mt-2">
|
<div class="text-sm mt-2"> Example: </div>
|
||||||
Example:
|
|
||||||
</div>
|
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{{ `${episodeNaming}` }}
|
{{ `${episodeNaming}` }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-sm mt-2">
|
<div class="text-sm mt-2"> Variables: </div>
|
||||||
Variables:
|
<div class="text-sm text-center"> {seriesName}, {seasonNumber}, {seasonNumberDD}, {episodeNumber}, {episodeNumberDD}, {quality} </div>
|
||||||
</div>
|
|
||||||
<div class="text-sm text-center">
|
|
||||||
{seriesName}, {seasonNumber}, {seasonNumberDD}, {episodeNumber}, {episodeNumberDD}, {quality}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col items-center p-3 bg-[#11111189] rounded-xl select-none">
|
<div class="flex flex-col items-center p-3 bg-[#11111189] rounded-xl select-none">
|
||||||
<div class="text-sm mb-2">Season Folder Naming</div>
|
<div class="text-sm mb-2">Season Folder Naming</div>
|
||||||
@ -32,30 +26,24 @@
|
|||||||
placeholder="Episode Naming"
|
placeholder="Episode Naming"
|
||||||
class="bg-[#5c5b5b] w-full focus:outline-none px-3 py-2 rounded-xl text-sm text-center"
|
class="bg-[#5c5b5b] w-full focus:outline-none px-3 py-2 rounded-xl text-sm text-center"
|
||||||
/>
|
/>
|
||||||
<div class="text-sm mt-2">
|
<div class="text-sm mt-2"> Example: </div>
|
||||||
Example:
|
|
||||||
</div>
|
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{{ `${seasonNaming}` }}
|
{{ `${seasonNaming}` }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-sm mt-2">
|
<div class="text-sm mt-2"> Variables: </div>
|
||||||
Variables:
|
<div class="text-sm text-center"> {seriesName}, {seasonNumber}, {seasonNumberDD}, {quality} </div>
|
||||||
</div>
|
|
||||||
<div class="text-sm text-center">
|
|
||||||
{seriesName}, {seasonNumber}, {seasonNumberDD}, {quality}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const episodeNumber = ref<number>(1);
|
const episodeNumber = ref<number>(1)
|
||||||
const seasonNumber = ref<number>(1);
|
const seasonNumber = ref<number>(1)
|
||||||
const quality = ref<number>(1080);
|
const quality = ref<number>(1080)
|
||||||
const seriesName = ref<string>('Frieren');
|
const seriesName = ref<string>('Frieren')
|
||||||
const episodeNamingTemplate = ref<string>();
|
const episodeNamingTemplate = ref<string>()
|
||||||
const seasonNamingTemplate = ref<string>();
|
const seasonNamingTemplate = ref<string>()
|
||||||
|
|
||||||
const episodeNaming = computed(() => {
|
const episodeNaming = computed(() => {
|
||||||
if (!episodeNamingTemplate.value) return
|
if (!episodeNamingTemplate.value) return
|
||||||
@ -65,8 +53,8 @@ const episodeNaming = computed(() => {
|
|||||||
.replace('{seasonNumberDD}', seasonNumber.value.toString().padStart(2, '0'))
|
.replace('{seasonNumberDD}', seasonNumber.value.toString().padStart(2, '0'))
|
||||||
.replace('{episodeNumber}', episodeNumber.value.toString())
|
.replace('{episodeNumber}', episodeNumber.value.toString())
|
||||||
.replace('{episodeNumberDD}', episodeNumber.value.toString().padStart(2, '0'))
|
.replace('{episodeNumberDD}', episodeNumber.value.toString().padStart(2, '0'))
|
||||||
.replace('{quality}', quality.value.toString() +'p');
|
.replace('{quality}', quality.value.toString() + 'p')
|
||||||
});
|
})
|
||||||
|
|
||||||
const seasonNaming = computed(() => {
|
const seasonNaming = computed(() => {
|
||||||
if (!seasonNamingTemplate.value) return
|
if (!seasonNamingTemplate.value) return
|
||||||
@ -74,8 +62,8 @@ const seasonNaming = computed(() => {
|
|||||||
.replace('{seriesName}', seriesName.value)
|
.replace('{seriesName}', seriesName.value)
|
||||||
.replace('{seasonNumber}', seasonNumber.value.toString())
|
.replace('{seasonNumber}', seasonNumber.value.toString())
|
||||||
.replace('{seasonNumberDD}', seasonNumber.value.toString().padStart(2, '0'))
|
.replace('{seasonNumberDD}', seasonNumber.value.toString().padStart(2, '0'))
|
||||||
.replace('{quality}', quality.value.toString() +'p');
|
.replace('{quality}', quality.value.toString() + 'p')
|
||||||
});
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
;(window as any).myAPI.getSeasonTemplate().then((result: string) => {
|
;(window as any).myAPI.getSeasonTemplate().then((result: string) => {
|
||||||
@ -111,7 +99,6 @@ const setSeasonTemplate = (name: string) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style>
|
<style></style>
|
||||||
|
@ -56,19 +56,35 @@
|
|||||||
<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 video'" 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 === 'downloading video'" 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 === 'decrypting video'" 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 === 'awaiting all dubs downloaded'" 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" />
|
<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 video & audio'" 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 === '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>
|
||||||
@ -77,10 +93,13 @@
|
|||||||
{{ p.status }}
|
{{ p.status }}
|
||||||
</div>
|
</div>
|
||||||
<div v-for="a in p.audiosdownloading">
|
<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">
|
<div
|
||||||
<Icon name="mdi:loading" class="h-3.5 w-3.5 text-white animate-spin" />
|
v-if="a.status && a.audio && a.status !== 'finished'"
|
||||||
{{ a.status }} Audio {{ a.audio }}
|
class="ml-2 flex flex-row items-center justify-center gap-1 text-xs capitalize p-1.5 bg-[#866332] rounded-lg"
|
||||||
</div>
|
>
|
||||||
|
<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>
|
</div>
|
||||||
@ -141,9 +160,9 @@ const playlist = ref<
|
|||||||
service: string
|
service: string
|
||||||
format: string
|
format: string
|
||||||
audiosdownloading: {
|
audiosdownloading: {
|
||||||
status: string,
|
status: string
|
||||||
audio: string
|
audio: string
|
||||||
}[]
|
}[]
|
||||||
}>
|
}>
|
||||||
>()
|
>()
|
||||||
|
|
||||||
@ -165,7 +184,7 @@ const getPlaylist = async () => {
|
|||||||
service: string
|
service: string
|
||||||
format: string
|
format: string
|
||||||
audiosdownloading: {
|
audiosdownloading: {
|
||||||
status: string,
|
status: string
|
||||||
audio: string
|
audio: string
|
||||||
}[]
|
}[]
|
||||||
}>
|
}>
|
||||||
|
@ -29,7 +29,20 @@ interface AccountCreateAttributes {
|
|||||||
|
|
||||||
interface PlaylistAttributes {
|
interface PlaylistAttributes {
|
||||||
id: number
|
id: number
|
||||||
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'
|
status:
|
||||||
|
| 'waiting'
|
||||||
|
| 'preparing'
|
||||||
|
| 'waiting for playlist'
|
||||||
|
| 'waiting for sub playlist'
|
||||||
|
| 'waiting for dub playlist'
|
||||||
|
| 'downloading'
|
||||||
|
| 'downloading video'
|
||||||
|
| '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 +62,20 @@ 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' | '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'
|
status:
|
||||||
|
| 'waiting'
|
||||||
|
| 'preparing'
|
||||||
|
| 'waiting for playlist'
|
||||||
|
| 'waiting for sub playlist'
|
||||||
|
| 'waiting for dub playlist'
|
||||||
|
| 'downloading'
|
||||||
|
| 'downloading video'
|
||||||
|
| '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'
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,14 @@ const crErrors = [
|
|||||||
// Crunchyroll Login Handler
|
// Crunchyroll Login Handler
|
||||||
export async function crunchyLogin(user: string, passw: string, geo: string) {
|
export async function crunchyLogin(user: string, passw: string, geo: string) {
|
||||||
var endpoint = await settings.get('CREndpoint')
|
var endpoint = await settings.get('CREndpoint')
|
||||||
const drmL3blob = await settings.get('l3blob')
|
const drmL3blob = await settings.has('l3blob')
|
||||||
const drmL3key = await settings.get('l3key')
|
const drmL3key = await settings.has('l3key')
|
||||||
|
|
||||||
if (!drmL3blob || !drmL3key) {
|
if (!drmL3blob || !drmL3key) {
|
||||||
|
endpoint = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!endpoint) {
|
||||||
await settings.set('CREndpoint', 1)
|
await settings.set('CREndpoint', 1)
|
||||||
endpoint = 1
|
endpoint = 1
|
||||||
}
|
}
|
||||||
@ -71,8 +75,8 @@ async function crunchyLoginFetchProxy(user: string, passw: string, geo: string)
|
|||||||
var body
|
var body
|
||||||
|
|
||||||
var endpoint = await settings.get('CREndpoint')
|
var endpoint = await settings.get('CREndpoint')
|
||||||
const drmL3blob = await settings.get('l3blob')
|
const drmL3blob = await settings.has('l3blob')
|
||||||
const drmL3key = await settings.get('l3key')
|
const drmL3key = await settings.has('l3key')
|
||||||
var proxy:
|
var proxy:
|
||||||
| {
|
| {
|
||||||
name: string
|
name: string
|
||||||
@ -189,10 +193,14 @@ async function crunchyLoginFetch(user: string, passw: string) {
|
|||||||
var body
|
var body
|
||||||
|
|
||||||
var endpoint = await settings.get('CREndpoint')
|
var endpoint = await settings.get('CREndpoint')
|
||||||
const drmL3blob = await settings.get('l3blob')
|
const drmL3blob = await settings.has('l3blob')
|
||||||
const drmL3key = await settings.get('l3key')
|
const drmL3key = await settings.has('l3key')
|
||||||
|
|
||||||
if (!drmL3blob || !drmL3key) {
|
if (!drmL3blob || !drmL3key) {
|
||||||
|
endpoint = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!endpoint) {
|
||||||
await settings.set('CREndpoint', 1)
|
await settings.set('CREndpoint', 1)
|
||||||
endpoint = 1
|
endpoint = 1
|
||||||
}
|
}
|
||||||
@ -274,6 +282,27 @@ async function crunchyLoginFetch(user: string, passw: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let counter = 0
|
||||||
|
var maxLimit = 0
|
||||||
|
|
||||||
|
async function incrementPlaylistCounter() {
|
||||||
|
return new Promise<void>((resolve) => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
if (counter < maxLimit) {
|
||||||
|
counter++
|
||||||
|
clearInterval(interval)
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrementPlaylistCounter() {
|
||||||
|
if (counter > 0) {
|
||||||
|
counter--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Crunchyroll Playlist Fetch
|
// Crunchyroll Playlist Fetch
|
||||||
export async function crunchyGetPlaylist(q: string, geo: string | undefined) {
|
export async function crunchyGetPlaylist(q: string, geo: string | undefined) {
|
||||||
const isProxyActive = await settings.get('proxyActive')
|
const isProxyActive = await settings.get('proxyActive')
|
||||||
@ -290,10 +319,14 @@ export async function crunchyGetPlaylist(q: string, geo: string | undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var endpoint = await settings.get('CREndpoint')
|
var endpoint = await settings.get('CREndpoint')
|
||||||
const drmL3blob = await settings.get('l3blob')
|
const drmL3blob = await settings.has('l3blob')
|
||||||
const drmL3key = await settings.get('l3key')
|
const drmL3key = await settings.has('l3key')
|
||||||
|
|
||||||
if (!drmL3blob || !drmL3key) {
|
if (!drmL3blob || !drmL3key) {
|
||||||
|
endpoint = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!endpoint) {
|
||||||
await settings.set('CREndpoint', 1)
|
await settings.set('CREndpoint', 1)
|
||||||
endpoint = 1
|
endpoint = 1
|
||||||
}
|
}
|
||||||
@ -383,6 +416,12 @@ export async function crunchyGetPlaylist(q: string, geo: string | undefined) {
|
|||||||
|
|
||||||
var playlist: VideoPlaylist
|
var playlist: VideoPlaylist
|
||||||
|
|
||||||
|
if (maxLimit === 0) {
|
||||||
|
maxLimit = await checkAccountMaxStreams()
|
||||||
|
}
|
||||||
|
|
||||||
|
await incrementPlaylistCounter()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`https://cr-play-service.prd.crunchyrollsvc.com/v1/${q}${
|
`https://cr-play-service.prd.crunchyrollsvc.com/v1/${q}${
|
||||||
@ -406,44 +445,12 @@ export async function crunchyGetPlaylist(q: string, geo: string | undefined) {
|
|||||||
playlist = data
|
playlist = data
|
||||||
} else {
|
} else {
|
||||||
const error = await response.text()
|
const error = await response.text()
|
||||||
const errorJSON: {
|
|
||||||
activeStreams: {
|
|
||||||
accountId: string
|
|
||||||
active: boolean
|
|
||||||
assetId: string
|
|
||||||
clientId: string
|
|
||||||
contentId: string
|
|
||||||
country: string
|
|
||||||
createdTimestamp: string
|
|
||||||
deviceSubtype: string
|
|
||||||
deviceType: string
|
|
||||||
episodeIdentity: string
|
|
||||||
id: string
|
|
||||||
token: string
|
|
||||||
}[]
|
|
||||||
} = await JSON.parse(error)
|
|
||||||
|
|
||||||
if (errorJSON && errorJSON.activeStreams && errorJSON.activeStreams.length !== 0) {
|
|
||||||
for (const e of errorJSON.activeStreams) {
|
|
||||||
await deleteVideoToken(e.contentId, e.token)
|
|
||||||
}
|
|
||||||
|
|
||||||
server.logger.log({
|
|
||||||
level: 'error',
|
|
||||||
message: 'Refetching Crunchyroll Video Playlist & Deleting all Video Token because too many streams',
|
|
||||||
error: errorJSON,
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
section: 'playlistCrunchyrollFetch'
|
|
||||||
})
|
|
||||||
|
|
||||||
return await crunchyGetPlaylist(q, geo)
|
|
||||||
}
|
|
||||||
|
|
||||||
messageBox('error', ['Cancel'], 2, 'Failed to get Crunchyroll Video Playlist', 'Failed to get Crunchyroll Video Playlist', error)
|
messageBox('error', ['Cancel'], 2, 'Failed to get Crunchyroll Video Playlist', 'Failed to get Crunchyroll Video Playlist', error)
|
||||||
server.logger.log({
|
server.logger.log({
|
||||||
level: 'error',
|
level: 'error',
|
||||||
message: 'Failed to get Crunchyroll Video Playlist',
|
message: 'Failed to get Crunchyroll Video Playlist',
|
||||||
error: errorJSON,
|
error: error,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
section: 'playlistCrunchyrollFetch'
|
section: 'playlistCrunchyrollFetch'
|
||||||
})
|
})
|
||||||
@ -466,6 +473,8 @@ export async function crunchyGetPlaylist(q: string, geo: string | undefined) {
|
|||||||
'User-Agent': 'Crunchyroll/1.8.0 Nintendo Switch/12.3.12.0 UE4/4.27'
|
'User-Agent': 'Crunchyroll/1.8.0 Nintendo Switch/12.3.12.0 UE4/4.27'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await incrementPlaylistCounter()
|
||||||
|
|
||||||
const responseProx = await fetch(
|
const responseProx = await fetch(
|
||||||
`https://cr-play-service.prd.crunchyrollsvc.com/v1/${q}${
|
`https://cr-play-service.prd.crunchyrollsvc.com/v1/${q}${
|
||||||
endpoints.find((e) => e.id === endpoint) ? endpoints.find((e) => e.id === endpoint)?.url : '/console/switch/play'
|
endpoints.find((e) => e.id === endpoint) ? endpoints.find((e) => e.id === endpoint)?.url : '/console/switch/play'
|
||||||
@ -502,6 +511,8 @@ export async function crunchyGetPlaylist(q: string, geo: string | undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await deleteVideoToken(q, dataProx.token)
|
await deleteVideoToken(q, dataProx.token)
|
||||||
|
} else {
|
||||||
|
decrementPlaylistCounter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -536,6 +547,9 @@ export async function deleteVideoToken(content: string, token: string) {
|
|||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
section: 'tokenDeletionCrunchyrollFetch'
|
section: 'tokenDeletionCrunchyrollFetch'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
decrementPlaylistCounter()
|
||||||
|
|
||||||
return 'ok'
|
return 'ok'
|
||||||
} else {
|
} else {
|
||||||
const error = await response.text()
|
const error = await response.text()
|
||||||
@ -605,7 +619,7 @@ export async function getAccountInfo() {
|
|||||||
if (!login) return
|
if (!login) return
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
Authorization: `Bearer ${login.access_token}`,
|
Authorization: `Bearer ${login.access_token}`
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -616,8 +630,8 @@ export async function getAccountInfo() {
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: {
|
const data: {
|
||||||
account_id: string,
|
account_id: string
|
||||||
external_id: string,
|
external_id: string
|
||||||
} = await JSON.parse(await response.text())
|
} = await JSON.parse(await response.text())
|
||||||
|
|
||||||
return data
|
return data
|
||||||
@ -640,7 +654,6 @@ export async function getAccountInfo() {
|
|||||||
|
|
||||||
// Check Max account streams because of crunchyroll activestream limit
|
// Check Max account streams because of crunchyroll activestream limit
|
||||||
export async function checkAccountMaxStreams() {
|
export async function checkAccountMaxStreams() {
|
||||||
|
|
||||||
const accountinfo = await getAccountInfo()
|
const accountinfo = await getAccountInfo()
|
||||||
|
|
||||||
if (!accountinfo) return 1
|
if (!accountinfo) return 1
|
||||||
@ -654,7 +667,7 @@ export async function checkAccountMaxStreams() {
|
|||||||
if (!login) return 1
|
if (!login) return 1
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
Authorization: `Bearer ${login.access_token}`,
|
Authorization: `Bearer ${login.access_token}`
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -666,22 +679,22 @@ export async function checkAccountMaxStreams() {
|
|||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: {
|
const data: {
|
||||||
items: {
|
items: {
|
||||||
__class__: string,
|
__class__: string
|
||||||
__href__: string,
|
__href__: string
|
||||||
__links__: string,
|
__links__: string
|
||||||
__actions__: string,
|
__actions__: string
|
||||||
benefit: string,
|
benefit: string
|
||||||
source: string
|
source: string
|
||||||
}[]
|
}[]
|
||||||
} = await JSON.parse(await response.text())
|
} = await JSON.parse(await response.text())
|
||||||
|
|
||||||
if (!data.items || data.items.length === 0) return 1
|
if (!data.items || data.items.length === 0) return 1
|
||||||
|
|
||||||
if (data.items.find(i => i.benefit === 'concurrent_streams.4')) return 2
|
if (data.items.find((i) => i.benefit === 'concurrent_streams.4')) return 2
|
||||||
|
|
||||||
if (data.items.find(i => i.benefit === 'concurrent_streams.1')) return 1
|
if (data.items.find((i) => i.benefit === 'concurrent_streams.1')) return 1
|
||||||
|
|
||||||
if (data.items.find(i => i.benefit === 'concurrent_streams.6')) return 3
|
if (data.items.find((i) => i.benefit === 'concurrent_streams.6')) return 3
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
} else {
|
} else {
|
||||||
@ -699,4 +712,4 @@ export async function checkAccountMaxStreams() {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(e as string)
|
throw new Error(e as string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,7 @@ export async function updatePlaylistByID(
|
|||||||
| 'waiting for sub playlist'
|
| 'waiting for sub playlist'
|
||||||
| 'waiting for dub playlist'
|
| 'waiting for dub playlist'
|
||||||
| 'downloading'
|
| 'downloading'
|
||||||
|
| 'downloading video'
|
||||||
| 'merging video'
|
| 'merging video'
|
||||||
| 'decrypting video'
|
| 'decrypting video'
|
||||||
| 'awaiting all dubs downloaded'
|
| 'awaiting all dubs downloaded'
|
||||||
@ -193,7 +194,7 @@ export async function updatePlaylistByID(
|
|||||||
section: 'playlistItemUpdateDatabase'
|
section: 'playlistItemUpdateDatabase'
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
messageBox('error', ['Cancel'], 2, 'Database Error', 'Failed to update playlist item', JSON.stringify(e))
|
messageBox('error', ['Cancel'], 2, 'Database Error', 'Failed to update playlist item', 'Failed to update playlist item')
|
||||||
server.logger.log({
|
server.logger.log({
|
||||||
level: 'error',
|
level: 'error',
|
||||||
message: 'Failed to update playlist item',
|
message: 'Failed to update playlist item',
|
||||||
@ -218,6 +219,7 @@ export async function addEpisodeToPlaylist(
|
|||||||
| 'waiting for sub playlist'
|
| 'waiting for sub playlist'
|
||||||
| 'waiting for dub playlist'
|
| 'waiting for dub playlist'
|
||||||
| 'downloading'
|
| 'downloading'
|
||||||
|
| 'downloading video'
|
||||||
| 'merging video'
|
| 'merging video'
|
||||||
| 'decrypting video'
|
| 'decrypting video'
|
||||||
| 'awaiting all dubs downloaded'
|
| 'awaiting all dubs downloaded'
|
||||||
@ -451,27 +453,6 @@ export async function downloadADNPlaylist(
|
|||||||
await deleteFolder(videoFolder)
|
await deleteFolder(videoFolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
var counter = 0
|
|
||||||
var maxLimit = 1
|
|
||||||
|
|
||||||
async function incrementPlaylistCounter() {
|
|
||||||
return new Promise<void>((resolve) => {
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
if (counter < maxLimit) {
|
|
||||||
counter++
|
|
||||||
clearInterval(interval)
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
}, 100)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function decrementPlaylistCounter() {
|
|
||||||
if (counter > 0) {
|
|
||||||
counter--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download Crunchyroll Playlist
|
// Download Crunchyroll Playlist
|
||||||
export async function downloadCrunchyrollPlaylist(
|
export async function downloadCrunchyrollPlaylist(
|
||||||
e: string,
|
e: string,
|
||||||
@ -488,15 +469,8 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
format: 'mp4' | 'mkv',
|
format: 'mp4' | 'mkv',
|
||||||
geo: string | undefined
|
geo: string | undefined
|
||||||
) {
|
) {
|
||||||
const accmaxstream = await checkAccountMaxStreams()
|
|
||||||
|
|
||||||
if (accmaxstream) {
|
|
||||||
maxLimit = accmaxstream
|
|
||||||
}
|
|
||||||
|
|
||||||
await updatePlaylistByID(downloadID, 'waiting for playlist')
|
await updatePlaylistByID(downloadID, 'waiting for playlist')
|
||||||
|
|
||||||
await incrementPlaylistCounter()
|
|
||||||
var playlist = await crunchyGetPlaylist(e, geo)
|
var playlist = await crunchyGetPlaylist(e, geo)
|
||||||
|
|
||||||
if (!playlist) {
|
if (!playlist) {
|
||||||
@ -517,8 +491,6 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
const found = playlist.data.versions.find((v) => v.audio_locale === 'ja-JP')
|
const found = playlist.data.versions.find((v) => v.audio_locale === 'ja-JP')
|
||||||
if (found) {
|
if (found) {
|
||||||
await deleteVideoToken(episodeID, playlist.data.token)
|
await deleteVideoToken(episodeID, playlist.data.token)
|
||||||
decrementPlaylistCounter()
|
|
||||||
await incrementPlaylistCounter()
|
|
||||||
playlist = await crunchyGetPlaylist(found.guid, found.geo)
|
playlist = await crunchyGetPlaylist(found.guid, found.geo)
|
||||||
} else {
|
} else {
|
||||||
console.log('Exact Playlist not found, taking what crunchy gives.')
|
console.log('Exact Playlist not found, taking what crunchy gives.')
|
||||||
@ -547,7 +519,6 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
}
|
}
|
||||||
|
|
||||||
await deleteVideoToken(episodeID, playlist.data.token)
|
await deleteVideoToken(episodeID, playlist.data.token)
|
||||||
decrementPlaylistCounter()
|
|
||||||
|
|
||||||
const subFolder = await createFolder()
|
const subFolder = await createFolder()
|
||||||
|
|
||||||
@ -600,7 +571,6 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
if (playlist.data.audioLocale !== 'ja-JP') {
|
if (playlist.data.audioLocale !== 'ja-JP') {
|
||||||
const foundStream = playlist.data.versions.find((v) => v.audio_locale === 'ja-JP')
|
const foundStream = playlist.data.versions.find((v) => v.audio_locale === 'ja-JP')
|
||||||
if (foundStream) {
|
if (foundStream) {
|
||||||
await incrementPlaylistCounter()
|
|
||||||
subPlaylist = await crunchyGetPlaylist(foundStream.guid, foundStream.geo)
|
subPlaylist = await crunchyGetPlaylist(foundStream.guid, foundStream.geo)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -641,7 +611,6 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
}
|
}
|
||||||
|
|
||||||
await deleteVideoToken(episodeID, subPlaylist.data.token)
|
await deleteVideoToken(episodeID, subPlaylist.data.token)
|
||||||
decrementPlaylistCounter()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await updatePlaylistByID(downloadID, 'waiting for dub playlist')
|
await updatePlaylistByID(downloadID, 'waiting for dub playlist')
|
||||||
@ -653,11 +622,9 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
await incrementPlaylistCounter()
|
|
||||||
const list = await crunchyGetPlaylist(found.guid, found.geo)
|
const list = await crunchyGetPlaylist(found.guid, found.geo)
|
||||||
if (list) {
|
if (list) {
|
||||||
await deleteVideoToken(episodeID, list.data.token)
|
await deleteVideoToken(episodeID, list.data.token)
|
||||||
decrementPlaylistCounter()
|
|
||||||
|
|
||||||
const foundSub = list.data.subtitles.find((sub) => sub.language === d)
|
const foundSub = list.data.subtitles.find((sub) => sub.language === d)
|
||||||
if (foundSub) {
|
if (foundSub) {
|
||||||
@ -699,7 +666,7 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await updatePlaylistByID(downloadID, 'downloading')
|
await updatePlaylistByID(downloadID, 'downloading video')
|
||||||
|
|
||||||
const subDownload = async () => {
|
const subDownload = async () => {
|
||||||
const sbs: Array<string> = []
|
const sbs: Array<string> = []
|
||||||
@ -713,7 +680,6 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
const audioDownload = async () => {
|
const audioDownload = async () => {
|
||||||
const audios: Array<string> = []
|
const audios: Array<string> = []
|
||||||
for (const v of dubDownloadList) {
|
for (const v of dubDownloadList) {
|
||||||
await incrementPlaylistCounter()
|
|
||||||
const list = await crunchyGetPlaylist(v.guid, v.geo)
|
const list = await crunchyGetPlaylist(v.guid, v.geo)
|
||||||
|
|
||||||
if (!list) return
|
if (!list) return
|
||||||
@ -723,7 +689,6 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
if (!playlist) return
|
if (!playlist) return
|
||||||
|
|
||||||
await deleteVideoToken(episodeID, list.data.token)
|
await deleteVideoToken(episodeID, list.data.token)
|
||||||
decrementPlaylistCounter()
|
|
||||||
|
|
||||||
const assetId = playlist.mediaGroups.AUDIO.audio.main.playlists[0].segments[0].resolvedUri.match(/\/assets\/(?:p\/)?([^_,]+)/)
|
const assetId = playlist.mediaGroups.AUDIO.audio.main.playlists[0].segments[0].resolvedUri.match(/\/assets\/(?:p\/)?([^_,]+)/)
|
||||||
|
|
||||||
@ -837,7 +802,6 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await incrementPlaylistCounter()
|
|
||||||
const play = await crunchyGetPlaylist(code, geo)
|
const play = await crunchyGetPlaylist(code, geo)
|
||||||
|
|
||||||
if (!play) {
|
if (!play) {
|
||||||
@ -882,7 +846,6 @@ export async function downloadCrunchyrollPlaylist(
|
|||||||
if (!mdp) return
|
if (!mdp) return
|
||||||
|
|
||||||
await deleteVideoToken(episodeID, play.data.token)
|
await deleteVideoToken(episodeID, play.data.token)
|
||||||
decrementPlaylistCounter()
|
|
||||||
|
|
||||||
var hq = mdp.playlists.find((i) => i.attributes.RESOLUTION?.height === quality)
|
var hq = mdp.playlists.find((i) => i.attributes.RESOLUTION?.height === quality)
|
||||||
|
|
||||||
|
@ -4,8 +4,7 @@ import fs from 'fs'
|
|||||||
import settings from 'electron-settings'
|
import settings from 'electron-settings'
|
||||||
|
|
||||||
export async function createFolder() {
|
export async function createFolder() {
|
||||||
|
var tempPath = (await settings.get('tempPath')) as string
|
||||||
var tempPath = await settings.get('tempPath') as string
|
|
||||||
|
|
||||||
if (!tempPath) {
|
if (!tempPath) {
|
||||||
tempPath = app.getPath('temp')
|
tempPath = app.getPath('temp')
|
||||||
@ -33,8 +32,7 @@ export async function checkDirectoryExistence(dir: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function createFolderName(name: string, dir: string) {
|
export async function createFolderName(name: string, dir: string) {
|
||||||
|
var tempPath = (await settings.get('tempPath')) as string
|
||||||
var tempPath = await settings.get('tempPath') as string
|
|
||||||
|
|
||||||
if (!tempPath) {
|
if (!tempPath) {
|
||||||
tempPath = app.getPath('temp')
|
tempPath = app.getPath('temp')
|
||||||
@ -69,8 +67,7 @@ export async function deleteFolder(folderPath: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteTemporaryFolders() {
|
export async function deleteTemporaryFolders() {
|
||||||
|
var tempPath = (await settings.get('tempPath')) as string
|
||||||
var tempPath = await settings.get('tempPath') as string
|
|
||||||
|
|
||||||
if (!tempPath) {
|
if (!tempPath) {
|
||||||
tempPath = app.getPath('temp')
|
tempPath = app.getPath('temp')
|
||||||
|
@ -18,6 +18,7 @@ var mainWindow: BrowserWindow
|
|||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
console.log('System info', { isProduction, platform, architucture })
|
console.log('System info', { isProduction, platform, architucture })
|
||||||
|
|
||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
title: 'Crunchyroll Downloader',
|
title: 'Crunchyroll Downloader',
|
||||||
icon: __dirname + '/icon/favicon.ico',
|
icon: __dirname + '/icon/favicon.ico',
|
||||||
@ -73,6 +74,11 @@ function createWindow() {
|
|||||||
// App events
|
// App events
|
||||||
// ==========
|
// ==========
|
||||||
app.whenReady().then(async () => {
|
app.whenReady().then(async () => {
|
||||||
|
settings.configure({
|
||||||
|
dir: app.getPath('documents') + '/Crunchyroll Downloader/settings/',
|
||||||
|
atomicSave: process.platform !== 'win32'
|
||||||
|
})
|
||||||
|
|
||||||
startAPI()
|
startAPI()
|
||||||
|
|
||||||
const mainWindow = createWindow()
|
const mainWindow = createWindow()
|
||||||
|
@ -22,5 +22,5 @@ contextBridge.exposeInMainWorld('myAPI', {
|
|||||||
setEpisodeTemplate: (name: string) => ipcRenderer.invoke('dialog:setEpisodeTemplate', name),
|
setEpisodeTemplate: (name: string) => ipcRenderer.invoke('dialog:setEpisodeTemplate', name),
|
||||||
getEpisodeTemplate: () => ipcRenderer.invoke('dialog:getEpisodeTemplate'),
|
getEpisodeTemplate: () => ipcRenderer.invoke('dialog:getEpisodeTemplate'),
|
||||||
setSeasonTemplate: (name: string) => ipcRenderer.invoke('dialog:setSeasonTemplate', name),
|
setSeasonTemplate: (name: string) => ipcRenderer.invoke('dialog:setSeasonTemplate', name),
|
||||||
getSeasonTemplate: () => ipcRenderer.invoke('dialog:getSeasonTemplate'),
|
getSeasonTemplate: () => ipcRenderer.invoke('dialog:getSeasonTemplate')
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user