added prettier

This commit is contained in:
Daniel Haller 2024-05-01 01:45:45 +02:00
parent 2e29f467d1
commit 9909e3b558
52 changed files with 5752 additions and 4129 deletions

View File

@ -11,7 +11,7 @@
"requirePragma": false,
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"tabWidth": 4,
"trailingComma": "none",
"useTabs": false,
"vueIndentScriptAndStyle": false,

View File

@ -1,72 +0,0 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const builder = require('electron-builder')
const Platform = builder.Platform
/**
* @type {import('electron-builder').Configuration}
*/
const options = {
appId: 'com.stratum.crunchyrolldownloader',
productName: 'Crunchyroll Downloader',
compression: 'maximum',
removePackageScripts: true,
nodeGypRebuild: true,
buildDependenciesFromSource: true,
publish: {
provider: 'github',
releaseType: 'release'
},
directories: {
output: 'crunchyroll-downloader-output-${version}'
},
win: {
artifactName: 'crunchyroll-downloader-${version}-windows-installer.${ext}',
icon: 'public/favicon.ico',
target: [
{
target: 'nsis',
arch: ['x64', 'ia32']
}
]
},
nsis: {
deleteAppDataOnUninstall: true
},
mac: {
category: 'public.app-category.entertainment',
hardenedRuntime: false,
gatekeeperAssess: false,
target: [
{
target: 'default',
arch: ['x64', 'arm64']
}
]
},
linux: {
maintainer: 'Stratum',
desktop: {
StartupNotify: 'false',
Encoding: 'UTF-8',
MimeType: 'x-scheme-handler/deeplink'
},
target: ['AppImage', 'rpm', 'deb']
}
}
const platform = 'WINDOWS'
builder
.build({
targets: Platform[platform].createTarget(),
config: options
})
.then((result) => {
console.log('----------------------------')
console.log('Platform:', platform)
console.log('Output:', JSON.stringify(result, null, 2))
})

72
build.ts Normal file
View File

@ -0,0 +1,72 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const builder = require('electron-builder')
const Platform = builder.Platform
/**
* @type {import('electron-builder').Configuration}
*/
const options = {
appId: 'com.stratum.crunchyrolldownloader',
productName: 'Crunchyroll Downloader',
compression: 'maximum',
removePackageScripts: true,
nodeGypRebuild: true,
buildDependenciesFromSource: true,
publish: {
provider: 'github',
releaseType: 'release'
},
directories: {
output: 'crunchyroll-downloader-output-${version}'
},
win: {
artifactName: 'crunchyroll-downloader-${version}-windows-installer.${ext}',
icon: 'public/favicon.ico',
target: [
{
target: 'nsis',
arch: ['x64', 'ia32']
}
]
},
nsis: {
deleteAppDataOnUninstall: true
},
mac: {
category: 'public.app-category.entertainment',
hardenedRuntime: false,
gatekeeperAssess: false,
target: [
{
target: 'default',
arch: ['x64', 'arm64']
}
]
},
linux: {
maintainer: 'Stratum',
desktop: {
StartupNotify: 'false',
Encoding: 'UTF-8',
MimeType: 'x-scheme-handler/deeplink'
},
target: ['AppImage', 'rpm', 'deb']
}
}
const platform = 'WINDOWS'
builder
.build({
targets: Platform[platform].createTarget(),
config: options
})
.then((result: any) => {
console.log('----------------------------')
console.log('Platform:', platform)
console.log('Output:', JSON.stringify(result, null, 2))
})

View File

@ -1,19 +1,16 @@
import type { ADNSearchFetch } from "./Types";
import type { ADNSearchFetch } from './Types'
export async function searchADN(q: string) {
const { data: deData, error: deError } = await useFetch<ADNSearchFetch>(
`https://gw.api.animationdigitalnetwork.fr/show/catalog`,
{
method: "GET",
const { data: deData, error: deError } = await useFetch<ADNSearchFetch>(`https://gw.api.animationdigitalnetwork.fr/show/catalog`, {
method: 'GET',
headers: {
"x-target-distribution": 'de',
'x-target-distribution': 'de'
},
query: {
"maxAgeCategory": "18",
"search": q
maxAgeCategory: '18',
search: q
}
}
);
})
if (deError.value) {
throw new Error(deError.value?.data.message as string)
@ -21,19 +18,16 @@ export async function searchADN(q: string) {
if (!deData.value) return
const { data: frData, error: frError } = await useFetch<ADNSearchFetch>(
`https://gw.api.animationdigitalnetwork.fr/show/catalog`,
{
method: "GET",
const { data: frData, error: frError } = await useFetch<ADNSearchFetch>(`https://gw.api.animationdigitalnetwork.fr/show/catalog`, {
method: 'GET',
headers: {
"x-target-distribution": 'fr',
'x-target-distribution': 'fr'
},
query: {
"maxAgeCategory": "18",
"search": q
maxAgeCategory: '18',
search: q
}
}
);
})
if (frError.value) {
throw new Error(frError.value?.data.message as string)
@ -41,22 +35,24 @@ export async function searchADN(q: string) {
if (!frData.value) return
const deShows = deData.value.shows;
const frShows = frData.value.shows;
const deShows = deData.value.shows
const frShows = frData.value.shows
const mergeLanguagesOfDuplicates = (shows: {
const mergeLanguagesOfDuplicates = (
shows: {
id: number
url: string
title: string
image2x: string
episodeCount: number,
episodeCount: number
languages: Array<string>
}[]) => {
shows.forEach(show => {
const existingShow = shows.find(s => s.id === show.id);
}[]
) => {
shows.forEach((show) => {
const existingShow = shows.find((s) => s.id === show.id)
if (existingShow) {
const existingShowIndex = shows.findIndex(s=> s === existingShow);
const rawLanguages = [...show.languages, ...existingShow.languages];
const existingShowIndex = shows.findIndex((s) => s === existingShow)
const rawLanguages = [...show.languages, ...existingShow.languages]
const languages: Array<string> = []
for (const l of rawLanguages) {
@ -66,13 +62,13 @@ export async function searchADN(q: string) {
}
show.languages = languages
}
});
return shows;
};
})
return shows
}
const allShows = mergeLanguagesOfDuplicates([...deShows, ...frShows]);
const allShows = mergeLanguagesOfDuplicates([...deShows, ...frShows])
const unique = [...new Map(allShows.map((s) => [s.id, s])).values()];
const unique = [...new Map(allShows.map((s) => [s.id, s])).values()]
return unique
}

View File

@ -4,8 +4,8 @@ export async function getEpisodesWithShowIdADN(id: number, lang: 'de' | 'fr') {
const { data, error } = await useFetch<ADNEpisodesFetch>(`https://gw.api.animationdigitalnetwork.fr/video/show/${id}?offset=0&limit=-1&order=asc`, {
method: 'GET',
headers: {
"x-target-distribution": lang,
},
'x-target-distribution': lang
}
})
if (error.value || !data.value) {

View File

@ -4,7 +4,7 @@ export interface ADNSearchFetch {
url: string
title: string
image2x: string
episodeCount: number,
episodeCount: number
languages: Array<string>
}>
}
@ -14,69 +14,69 @@ export interface ADNEpisodesFetch {
}
export interface ADNEpisode {
id: number,
title: string,
name: string,
number: string,
shortNumber: string,
season: string,
reference: string,
type: string,
order: number,
image: string,
image2x: string,
summary: string,
releaseDate: string,
duration: number,
url: string,
urlPath: string,
embeddedUrl: string,
languages: Array<string>,
qualities: Array<string>,
rating: number,
ratingsCount: number,
commentsCount: number,
available: boolean,
download: boolean,
free: boolean,
freeWithAds: boolean,
id: number
title: string
name: string
number: string
shortNumber: string
season: string
reference: string
type: string
order: number
image: string
image2x: string
summary: string
releaseDate: string
duration: number
url: string
urlPath: string
embeddedUrl: string
languages: Array<string>
qualities: Array<string>
rating: number
ratingsCount: number
commentsCount: number
available: boolean
download: boolean
free: boolean
freeWithAds: boolean
show: {
id: number,
title: string,
type: string,
originalTitle: string,
shortTitle: string,
reference: string,
age: string,
languages: Array<string>,
summary: string,
image: string,
image2x: string,
imageHorizontal: string,
imageHorizontal2x: string,
url: string,
urlPath: string,
episodeCount: number,
genres: Array<string>,
copyright: string,
rating: number,
ratingsCount: number,
commentsCount: number,
qualities: Array<string>,
simulcast: boolean,
free: boolean,
available: boolean,
download: boolean,
basedOn: string,
tagline: Array<string>,
firstReleaseYear: string,
productionStudio: string,
countryOfOrigin: string,
id: number
title: string
type: string
originalTitle: string
shortTitle: string
reference: string
age: string
languages: Array<string>
summary: string
image: string
image2x: string
imageHorizontal: string
imageHorizontal2x: string
url: string
urlPath: string
episodeCount: number
genres: Array<string>
copyright: string
rating: number
ratingsCount: number
commentsCount: number
qualities: Array<string>
simulcast: boolean
free: boolean
available: boolean
download: boolean
basedOn: string
tagline: Array<string>
firstReleaseYear: string
productionStudio: string
countryOfOrigin: string
productionTeam: Array<{
role: string,
name: string,
}>,
nextVideoReleaseDate: string,
role: string
name: string
}>
nextVideoReleaseDate: string
indexable: boolean
}
indexable: boolean

View File

@ -1,70 +1,72 @@
export interface CrunchyEpisode {
closed_captions_available: boolean,
availability_notes: string,
next_episode_title: string,
upload_date: string,
closed_captions_available: boolean
availability_notes: string
next_episode_title: string
upload_date: string
versions: Array<{
audio_locale: string,
guid: string,
is_premium_only: boolean,
media_guid: string,
original: boolean,
season_guid: string,
audio_locale: string
guid: string
is_premium_only: boolean
media_guid: string
original: boolean
season_guid: string
variant: string
}>,
season_slug_title: string,
series_title: string,
season_title: string,
sequence_number: number,
maturity_ratings: Array<string>,
slug_title: string,
is_premium_only: boolean,
availability_ends: string,
identifier: string,
recent_variant: string,
free_available_date: string,
subtitle_locales: Array<string>,
series_id: string,
mature_blocked: boolean,
duration_ms: number,
availability_starts: string,
audio_locale: string,
}>
season_slug_title: string
series_title: string
season_title: string
sequence_number: number
maturity_ratings: Array<string>
slug_title: string
is_premium_only: boolean
availability_ends: string
identifier: string
recent_variant: string
free_available_date: string
subtitle_locales: Array<string>
series_id: string
mature_blocked: boolean
duration_ms: number
availability_starts: string
audio_locale: string
images: {
thumbnail: Array<Array<{
height: number,
source: string,
type: string,
thumbnail: Array<
Array<{
height: number
source: string
type: string
width: number
}>>
},
season_sequence_number: number,
season_id: string,
episode_number: number,
listing_id: string,
available_date: string,
channel_id: string,
season_number: number,
hd_flag: boolean,
recent_audio_locale: string,
available_offline: boolean,
episode: string,
is_subbed: boolean,
media_type: string,
is_clip: boolean,
title: string,
streams_link: string,
slug: string,
id: string,
production_episode_id: string,
is_dubbed: boolean,
next_episode_id: string,
series_slug_title: string,
season_tags: Array<string>,
premium_date: string,
is_mature: boolean,
premium_available_date: string,
description: string,
episode_air_date: string,
}>
>
}
season_sequence_number: number
season_id: string
episode_number: number
listing_id: string
available_date: string
channel_id: string
season_number: number
hd_flag: boolean
recent_audio_locale: string
available_offline: boolean
episode: string
is_subbed: boolean
media_type: string
is_clip: boolean
title: string
streams_link: string
slug: string
id: string
production_episode_id: string
is_dubbed: boolean
next_episode_id: string
series_slug_title: string
season_tags: Array<string>
premium_date: string
is_mature: boolean
premium_available_date: string
description: string
episode_air_date: string
eligible_region: string
}

View File

@ -1,16 +1,21 @@
<template>
<div class="fixed w-full flex flex-row px-2 bg-[#11111189] h-14 z-10 gap-1" style="-webkit-app-region: drag">
<div class="w-full flex gap-10 flex-row items-center justify-center px-5">
<button @click="openAddAnime" class="flex items-center justify-center px-2 py-2 gap-1 transition-all bg-[#ffffff16] hover:bg-[#ffffff25] rounded-lg select-none" style="-webkit-app-region: no-drag">
<button
@click="openAddAnime"
class="flex items-center justify-center px-2 py-2 gap-1 transition-all bg-[#ffffff16] hover:bg-[#ffffff25] rounded-lg select-none"
style="-webkit-app-region: no-drag"
>
<Icon name="ph:plus-bold" class="h-3.5 w-3.5 text-white" />
<div class="text-[11px] text-white font-dm">
ADD DOWNLOAD
</div>
<div class="text-[11px] text-white font-dm"> ADD DOWNLOAD </div>
</button>
</div>
<div class="w-full flex flex-row items-center justify-center">
<img src="/logo.png" class="h-8">
<div class="text-[10px] leading-[10px] text-opacity-90 text-white select-none">Crunchyroll <br> Downloader</div>
<img src="/logo.png" class="h-8" />
<div class="text-[10px] leading-[10px] text-opacity-90 text-white select-none"
>Crunchyroll <br />
Downloader</div
>
</div>
<div class="w-full flex gap-2 flex-row items-center justify-center">
<!-- <button class="flex items-center justify-center px-2 py-2 gap-1 transition-all bg-[#ffffff16] hover:bg-[#ffffff25] rounded-lg select-none" style="-webkit-app-region: no-drag">
@ -19,11 +24,13 @@
PLAYLIST
</div>
</button> -->
<button @click="openSettings" class="flex items-center justify-center px-2 py-2 gap-1 transition-all bg-[#ffffff16] hover:bg-[#ffffff25] rounded-lg select-none" style="-webkit-app-region: no-drag">
<button
@click="openSettings"
class="flex items-center justify-center px-2 py-2 gap-1 transition-all bg-[#ffffff16] hover:bg-[#ffffff25] rounded-lg select-none"
style="-webkit-app-region: no-drag"
>
<Icon name="ic:round-settings" class="h-3.5 w-3.5 text-white" />
<div class="text-[11px] text-white font-dm">
SETTINGS
</div>
<div class="text-[11px] text-white font-dm"> SETTINGS </div>
</button>
</div>
</div>
@ -36,12 +43,12 @@ import { openNewWindow } from './Functions/WindowHandler'
const isProduction = process.env.NODE_ENV !== 'development'
async function openSettings() {
(window as any).myAPI.openWindow({
title: "Settings",
;(window as any).myAPI.openWindow({
title: 'Settings',
url: isProduction ? 'http://localhost:8079/settings' : 'http://localhost:3000/settings',
width: 600,
height: 700,
backgroundColor: "#111111"
backgroundColor: '#111111'
})
}
@ -59,12 +66,12 @@ async function openAddAnime() {
// return
// }
(window as any).myAPI.openWindow({
title: "Add Anime",
;(window as any).myAPI.openWindow({
title: 'Add Anime',
url: isProduction ? 'http://localhost:8079/addanime' : 'http://localhost:3000/addanime',
width: 700,
height: 450,
backgroundColor: "#111111"
backgroundColor: '#111111'
})
}
</script>

View File

@ -1,7 +1,11 @@
<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'"
: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" />

View File

@ -14,7 +14,8 @@
"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 build && pnpm transpile-src && node build.js"
"build:electron": "pnpm build && pnpm transpile-src && node build.ts",
"prettier:fix": "pnpm prettier src --write && pnpm prettier components --write && pnpm prettier pages --write && pnpm prettier build.ts --write"
},
"devDependencies": {
"7zip-bin": "^5.2.0",
@ -27,12 +28,11 @@
"dotenv": "^16.4.5",
"electron": "^30.0.1",
"electron-builder": "^24.13.3",
"eslint": "^8.57.0",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-prettier": "^4.2.1",
"nuxt": "^3.11.2",
"nuxt-icon": "^0.6.10",
"prettier": "^2.8.8",
"prettier": "^3.2.5",
"sass": "^1.75.0",
"sass-loader": "^13.3.3",
"tsc-watch": "^6.2.0",

View File

@ -20,13 +20,11 @@
</select>
</div>
<div v-if="(isLoggedInCR && service === 'crunchyroll') || (isLoggedInADN && service === 'adn')" class="relative flex flex-col">
<input
v-model="search"
@input="handleInputChange"
placeholder="SEARCH"
class="bg-[#5c5b5b] focus:outline-none px-3 py-3 rounded-xl text-sm text-center"
/>
<div class="absolute top-full left-0 h-28 w-full bg-[#868585] rounded-xl z-10 flex items-center justify-center transition-all duration-300" :class="isFetchingResults ? 'opacity-100' : 'opacity-0 pointer-events-none'">
<input v-model="search" @input="handleInputChange" placeholder="SEARCH" class="bg-[#5c5b5b] focus:outline-none px-3 py-3 rounded-xl text-sm text-center" />
<div
class="absolute top-full left-0 h-28 w-full bg-[#868585] rounded-xl z-10 flex items-center justify-center transition-all duration-300"
:class="isFetchingResults ? 'opacity-100' : 'opacity-0 pointer-events-none'"
>
<Icon name="mdi:loading" class="h-8 w-8 animate-spin" />
</div>
<div
@ -258,7 +256,12 @@
</div>
<div class="flex flex-row gap-3">
<div v-if="service === 'crunchyroll'" class="relative flex flex-col w-full">
<select v-model="hardsub" name="episode" class="bg-[#5c5b5b] focus:outline-none px-3 py-2 rounded-xl text-sm text-center cursor-pointer" :disabled="isHardsubDisabled">
<select
v-model="hardsub"
name="episode"
class="bg-[#5c5b5b] focus:outline-none px-3 py-2 rounded-xl text-sm text-center cursor-pointer"
:disabled="isHardsubDisabled"
>
<option :value="false" class="text-sm text-slate-200">Hardsub: false</option>
<option :value="true" class="text-sm text-slate-200">Hardsub: true</option>
</select>
@ -788,26 +791,27 @@ const addToPlaylistADN = async () => {
}
.font-dm {
font-family: "DM Sans", sans-serif;
font-family: 'DM Sans', sans-serif;
}
.font-protest {
font-family: "Protest Riot", sans-serif;
font-family: 'Protest Riot', sans-serif;
font-weight: 400;
font-style: normal;
}
.font-dm-big {
font-family: "DM Sans", sans-serif;
font-family: 'DM Sans', sans-serif;
font-weight: 1000;
font-style: normal;
}
select {
background: url("data:image/svg+xml,<svg height='10px' width='10px' viewBox='0 0 16 16' fill='%23000000' xmlns='http://www.w3.org/2000/svg'><path d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/></svg>") no-repeat;
background: url("data:image/svg+xml,<svg height='10px' width='10px' viewBox='0 0 16 16' fill='%23000000' xmlns='http://www.w3.org/2000/svg'><path d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/></svg>")
no-repeat;
background-position: calc(100% - 0.75rem) center !important;
background-color: #5c5b5b;
-moz-appearance:none !important;
-moz-appearance: none !important;
-webkit-appearance: none !important;
appearance: none !important;
}

View File

@ -58,17 +58,17 @@ const login = async () => {
<style>
.font-dm {
font-family: "DM Sans", sans-serif;
font-family: 'DM Sans', sans-serif;
}
.font-protest {
font-family: "Protest Riot", sans-serif;
font-family: 'Protest Riot', sans-serif;
font-weight: 400;
font-style: normal;
}
.font-dm-big {
font-family: "DM Sans", sans-serif;
font-family: 'DM Sans', sans-serif;
font-weight: 1000;
font-style: normal;
}

View File

@ -58,17 +58,17 @@ const login = async () => {
<style>
.font-dm {
font-family: "DM Sans", sans-serif;
font-family: 'DM Sans', sans-serif;
}
.font-protest {
font-family: "Protest Riot", sans-serif;
font-family: 'Protest Riot', sans-serif;
font-weight: 400;
font-style: normal;
}
.font-dm-big {
font-family: "DM Sans", sans-serif;
font-family: 'DM Sans', sans-serif;
font-weight: 1000;
font-style: normal;
}

View File

@ -7,7 +7,10 @@
Delete Playlist
</button> -->
<div v-for="p in playlist" class="relative flex flex-row gap-4 min-h-36 bg-[#63636383] rounded-xl font-dm overflow-hidden">
<div class="absolute top-0 left-0 w-full h-full bg-[#a1a1a141] transition-all duration-300" :style="`width: calc((${p.partsdownloaded} / ${p.partsleft}) * 100%);`"></div>
<div
class="absolute top-0 left-0 w-full h-full bg-[#a1a1a141] transition-all duration-300"
:style="`width: calc((${p.partsdownloaded} / ${p.partsleft}) * 100%);`"
></div>
<div class="absolute h-full w-full flex flex-row gap-3 p-3.5">
<div v-if="p.service === 'CR'" class="flex w-48 min-w-48">
<img :src="(p.media as CrunchyEpisode).images.thumbnail[0].find((p) => p.height === 1080)?.source" alt="Image" class="object-cover rounded-lg" />
@ -44,7 +47,8 @@
</div>
</div>
<div v-if="p.service === 'CR'" class="text-base capitalize h-full flex items-center">
{{ (p.media as CrunchyEpisode).series_title }} Season {{ (p.media as CrunchyEpisode).season_number }} Episode {{ (p.media as CrunchyEpisode).episode_number }}
{{ (p.media as CrunchyEpisode).series_title }} Season {{ (p.media as CrunchyEpisode).season_number }} Episode
{{ (p.media as CrunchyEpisode).episode_number }}
</div>
<div v-if="p.service === 'ADN'" class="text-base capitalize h-full">
{{ (p.media as ADNEpisode).show.title }} Season {{ (p.media as ADNEpisode).season ? (p.media as ADNEpisode).season : 1 }} Episode

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
@echo off
wait-on http://localhost:3000 && electron ./.output/src/electron/background.js

View File

@ -1,46 +1,45 @@
import fastify from "fastify";
import cors from "@fastify/cors";
import NodeCache from "node-cache";
import crunchyrollRoutes from "./routes/crunchyroll/crunchyroll.route";
import { sequelize } from "./db/database";
import serviceRoutes from "./routes/service/service.route";
(async () => {
import fastify from 'fastify'
import cors from '@fastify/cors'
import NodeCache from 'node-cache'
import crunchyrollRoutes from './routes/crunchyroll/crunchyroll.route'
import { sequelize } from './db/database'
import serviceRoutes from './routes/service/service.route'
;(async () => {
try {
await sequelize.authenticate();
console.log("Connection has been established successfully.");
await sequelize.authenticate()
console.log('Connection has been established successfully.')
} catch (error) {
console.error("Unable to connect to the database:", error);
console.error('Unable to connect to the database:', error)
}
try {
await sequelize.sync();
console.log("All models were synchronized successfully.");
await sequelize.sync()
console.log('All models were synchronized successfully.')
} catch (error) {
console.log("Failed to synchronize Models");
console.log('Failed to synchronize Models')
}
})();
})()
const CacheController = new NodeCache({ stdTTL: 100, checkperiod: 120 });
const CacheController = new NodeCache({ stdTTL: 100, checkperiod: 120 })
export const server = fastify();
export const server = fastify()
// Cors registration
server.register(cors, {
origin: "*",
methods: ["GET", "POST", "PUT", "DELETE"],
allowedHeaders: ["Content-Type", "Authorization"],
});
origin: '*',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
})
// Cache Controller Type
declare module "fastify" {
declare module 'fastify' {
interface FastifyInstance {
CacheController: NodeCache;
CacheController: NodeCache
}
}
// Cache Controller
server.decorate("CacheController", CacheController);
server.decorate('CacheController', CacheController)
// Routes
server.register(crunchyrollRoutes, { prefix: 'api/crunchyroll' })
@ -49,11 +48,11 @@ server.register(serviceRoutes, { prefix: 'api/service' })
function startAPI() {
server.listen({ port: 8080 }, (err, address) => {
if (err) {
console.error(err);
return;
console.error(err)
return
}
console.log(`Server is listening on ${address}`);
});
console.log(`Server is listening on ${address}`)
})
}
export default startAPI;
export default startAPI

View File

@ -36,8 +36,8 @@ interface PlaylistAttributes {
hardsub: boolean
quality: 1080 | 720 | 480 | 360 | 240
dir: string
failedreason: string,
service: 'CR' | 'ADN',
failedreason: string
service: 'CR' | 'ADN'
format: 'mp4' | 'mkv'
}
@ -48,8 +48,8 @@ interface PlaylistCreateAttributes {
dir: string
quality: 1080 | 720 | 480 | 360 | 240
hardsub: boolean
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'completed' | 'failed',
service: 'CR' | 'ADN',
status: 'waiting' | 'preparing' | 'downloading' | 'merging' | 'completed' | 'failed'
service: 'CR' | 'ADN'
format: 'mp4' | 'mkv'
}

View File

@ -103,7 +103,6 @@ export async function getEpisodeADN(q: number) {
}
export async function getPlayerConfigADN(id: number, geo: 'de' | 'fr') {
const account = await loggedInCheck('ADN')
if (!account) return
@ -216,7 +215,7 @@ export async function adnGetPlaylist(animeid: number, geo: 'de' | 'fr') {
const data: ADNLink = await JSON.parse(await response.text())
return { data: data, secret: token.random }
} else {
const data: { message: string, code: string, statusCode: string} = JSON.parse(await response.text())
const data: { message: string; code: string; statusCode: string } = JSON.parse(await response.text())
messageBox('error', ['Cancel'], 2, 'Failed to fetch Playlist', 'Failed to fetch ADN Playlist', `${data.message} - ${data.code}`)
@ -230,14 +229,14 @@ export async function adnGetPlaylist(animeid: number, geo: 'de' | 'fr') {
export async function adnGetM3U8Playlist(url: string) {
try {
const response = await fetch(url, {
method: 'GET',
method: 'GET'
})
if (response.ok) {
const data: { location: string } = await JSON.parse(await response.text())
const mu8 = await fetch(data.location, {
method: 'GET',
method: 'GET'
})
const playlist = await mu8.text()
@ -245,12 +244,12 @@ export async function adnGetM3U8Playlist(url: string) {
const url = await extractURLFromPlaylist(playlist)
const partsraw = await fetch(url, {
method: 'GET',
method: 'GET'
})
const parts = await partsraw.text()
const baseurl = await extractBaseURL(url);
const baseurl = await extractBaseURL(url)
const partsArray = await extractSequenceURLs(parts, baseurl)
@ -262,26 +261,26 @@ export async function adnGetM3U8Playlist(url: string) {
}
async function extractURLFromPlaylist(playlist: string) {
var startIndex = playlist.indexOf("http");
var endIndex = playlist.indexOf(" ", startIndex);
var extractedURL = playlist.slice(startIndex, endIndex);
return extractedURL;
var startIndex = playlist.indexOf('http')
var endIndex = playlist.indexOf(' ', startIndex)
var extractedURL = playlist.slice(startIndex, endIndex)
return extractedURL
}
async function extractBaseURL(playlistURL: string) {
var baseURL = playlistURL.substring(0, playlistURL.lastIndexOf("/") + 1);
return baseURL;
var baseURL = playlistURL.substring(0, playlistURL.lastIndexOf('/') + 1)
return baseURL
}
async function extractSequenceURLs(playlistText: string, baseURL: string) {
var sequenceURLs: Array<{ filename: string, url: string }> = [];
var matches = playlistText.match(/sequence_\d+\.ts/g);
var sequenceURLs: Array<{ filename: string; url: string }> = []
var matches = playlistText.match(/sequence_\d+\.ts/g)
if (matches) {
matches.forEach(function(match) {
sequenceURLs.push({ filename: match, url: baseURL + match });
});
matches.forEach(function (match) {
sequenceURLs.push({ filename: match, url: baseURL + match })
})
}
return sequenceURLs;
return sequenceURLs
}
export async function parseSubs(url: string, secret: string) {

View File

@ -1,14 +1,17 @@
import { FastifyReply, FastifyRequest } from "fastify"
import { crunchyLogin } from "../crunchyroll/crunchyroll.service"
import { addEpisodeToPlaylist, getDownloading, getPlaylist, loggedInCheck, safeLoginData } from "./service.service"
import { CrunchyEpisodes } from "../../types/crunchyroll"
import { adnLogin } from "../adn/adn.service"
import { FastifyReply, FastifyRequest } from 'fastify'
import { crunchyLogin } from '../crunchyroll/crunchyroll.service'
import { addEpisodeToPlaylist, getDownloading, getPlaylist, loggedInCheck, safeLoginData } from './service.service'
import { CrunchyEpisodes } from '../../types/crunchyroll'
import { adnLogin } from '../adn/adn.service'
export async function checkLoginController(request: FastifyRequest<{
export async function checkLoginController(
request: FastifyRequest<{
Params: {
id: string
}
}>, reply: FastifyReply) {
}>,
reply: FastifyReply
) {
const account = await loggedInCheck(request.params.id)
if (!account) {
@ -23,7 +26,7 @@ export async function loginController(
Body: {
user: string
password: string
},
}
Params: {
id: string
}
@ -44,14 +47,12 @@ export async function loginController(
if (params.id === 'CR') {
const { data, error } = await crunchyLogin(body.user, body.password)
responseError = error,
responseData = data
;(responseError = error), (responseData = data)
}
if (params.id === 'ADN') {
const { data, error } = await adnLogin(body.user, body.password)
responseError = error,
responseData = data
;(responseError = error), (responseData = data)
}
if (responseError || !responseData) {

View File

@ -1,5 +1,5 @@
import { FastifyInstance } from "fastify"
import { addPlaylistController, checkLoginController, getPlaylistController, loginController } from "./service.controller"
import { FastifyInstance } from 'fastify'
import { addPlaylistController, checkLoginController, getPlaylistController, loginController } from './service.controller'
async function serviceRoutes(server: FastifyInstance) {
server.post(
@ -58,6 +58,6 @@ async function serviceRoutes(server: FastifyInstance) {
},
getPlaylistController
)
}
}
export default serviceRoutes
export default serviceRoutes

View File

@ -290,14 +290,7 @@ export async function downloadADNPlaylist(
return
}
await mergeVideoFile(
file as string,
[],
subss,
seasonFolder,
`${name.replace(/[/\\?%*:|"<>]/g, '')} Season ${season} Episode ${episode}`,
format
)
await mergeVideoFile(file as string, [], subss, seasonFolder, `${name.replace(/[/\\?%*:|"<>]/g, '')} Season ${season} Episode ${episode}`, format)
await updatePlaylistByID(downloadID, 'completed')

View File

@ -54,20 +54,20 @@ export async function deleteFolder(folderPath: string) {
}
export async function deleteTemporaryFolders() {
const documentsPath = app.getPath('documents');
const folderPrefix = 'crd-tmp-';
const documentsPath = app.getPath('documents')
const folderPrefix = 'crd-tmp-'
try {
const files = await fs.promises.readdir(documentsPath);
const tempFolders = files.filter(file => file.startsWith(folderPrefix));
const files = await fs.promises.readdir(documentsPath)
const tempFolders = files.filter((file) => file.startsWith(folderPrefix))
for (const folder of tempFolders) {
const folderPath = path.join(documentsPath, folder);
await deleteFolder(folderPath);
console.log(`Temporary folder ${folder} deleted.`);
const folderPath = path.join(documentsPath, folder)
await deleteFolder(folderPath)
console.log(`Temporary folder ${folder} deleted.`)
}
} catch (error) {
console.error('Error deleting temporary folders:', error);
throw error;
console.error('Error deleting temporary folders:', error)
throw error
}
}

View File

@ -76,70 +76,70 @@ export interface ADNLink {
}
export interface ADNEpisode {
id: number,
title: string,
name: string,
number: string,
shortNumber: string,
season: string,
reference: string,
type: string,
order: number,
image: string,
image2x: string,
summary: string,
releaseDate: string,
duration: number,
url: string,
urlPath: string,
embeddedUrl: string,
languages: Array<string>,
qualities: Array<string>,
rating: number,
ratingsCount: number,
commentsCount: number,
available: boolean,
download: boolean,
free: boolean,
freeWithAds: boolean,
id: number
title: string
name: string
number: string
shortNumber: string
season: string
reference: string
type: string
order: number
image: string
image2x: string
summary: string
releaseDate: string
duration: number
url: string
urlPath: string
embeddedUrl: string
languages: Array<string>
qualities: Array<string>
rating: number
ratingsCount: number
commentsCount: number
available: boolean
download: boolean
free: boolean
freeWithAds: boolean
show: {
id: number,
title: string,
type: string,
originalTitle: string,
shortTitle: string,
reference: string,
age: string,
languages: Array<string>,
summary: string,
image: string,
image2x: string,
imageHorizontal: string,
imageHorizontal2x: string,
url: string,
urlPath: string,
episodeCount: number,
genres: Array<string>,
copyright: string,
rating: number,
ratingsCount: number,
commentsCount: number,
qualities: Array<string>,
simulcast: boolean,
free: boolean,
available: boolean,
download: boolean,
basedOn: string,
tagline: Array<string>,
firstReleaseYear: string,
productionStudio: string,
countryOfOrigin: string,
id: number
title: string
type: string
originalTitle: string
shortTitle: string
reference: string
age: string
languages: Array<string>
summary: string
image: string
image2x: string
imageHorizontal: string
imageHorizontal2x: string
url: string
urlPath: string
episodeCount: number
genres: Array<string>
copyright: string
rating: number
ratingsCount: number
commentsCount: number
qualities: Array<string>
simulcast: boolean
free: boolean
available: boolean
download: boolean
basedOn: string
tagline: Array<string>
firstReleaseYear: string
productionStudio: string
countryOfOrigin: string
productionTeam: Array<{
role: string,
name: string,
}>,
nextVideoReleaseDate: string,
role: string
name: string
}>
nextVideoReleaseDate: string
indexable: boolean
}
indexable: boolean
}
}

View File

@ -2,7 +2,7 @@ import { BrowserWindow, ipcMain } from 'electron'
import { autoUpdater } from 'electron-updater'
import log from 'electron-log'
var status: { status: string, info: any } = { status: "", info: null }
var status: { status: string; info: any } = { status: '', info: null }
autoUpdater.logger = log
;(autoUpdater.logger as typeof log).transports.file.level = 'info'
@ -56,9 +56,12 @@ export default (mainWindow: BrowserWindow) => {
autoUpdater.checkForUpdates()
setInterval(() => {
setInterval(
() => {
autoUpdater.checkForUpdates()
}, 1000 * 60 * 60 * 2)
},
1000 * 60 * 60 * 2
)
console.log('[-] MODULE::updater Initialized')
}

View File

@ -1,16 +1,10 @@
import {contextBridge, ipcRenderer} from 'electron'
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('myAPI', {
selectFolder: () => ipcRenderer.invoke('dialog:openDirectory'),
getFolder: () => ipcRenderer.invoke('dialog:defaultDirectory'),
openWindow: (opt: {
title: string,
url: string,
width: number,
height: number,
backgroundColor: string
}) => ipcRenderer.invoke('window:openNewWindow', opt),
openWindow: (opt: { title: string; url: string; width: number; height: number; backgroundColor: string }) => ipcRenderer.invoke('window:openNewWindow', opt),
getUpdateStatus: () => ipcRenderer.invoke('updater:getUpdateStatus'),
startUpdateDownload: () => ipcRenderer.invoke('updater:download'),
startUpdateInstall: () => ipcRenderer.invoke('updater:quitAndInstall'),
startUpdateInstall: () => ipcRenderer.invoke('updater:quitAndInstall')
})

View File

@ -44,7 +44,7 @@
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
"declaration": false, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
"declaration": false /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */

View File

@ -1,9 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json",
"compilerOptions": {
"types": [
"@nuxtjs/i18n",
]
}
}