adn login implementation and search not disappearing fix

This commit is contained in:
Daniel Haller 2024-04-22 16:43:55 +02:00
parent f19189f1dc
commit a4d3f8a34e
6 changed files with 193 additions and 97 deletions

View File

View File

View File

@ -19,7 +19,7 @@
<option value="adn">ADN</option>
</select>
</div>
<div v-if="isLoggedInCR && service === 'crunchyroll' || !isLoggedInCR && service === 'adn'" class="relative flex flex-col">
<div v-if="isLoggedInCR && service === 'crunchyroll' || isLoggedInADN && service === 'adn'" class="relative flex flex-col">
<input
v-model="search"
@input="handleInputChange"
@ -33,7 +33,7 @@
</div>
<div
v-if="searchActive"
class="absolute top-full left-0 h-60 w-full bg-[#868585] rounded-xl overflow-y-scroll grid grid-cols-2 gap-3 p-2 z-10"
class="absolute top-full left-0 h-40 w-full bg-[#868585] rounded-xl overflow-y-scroll grid grid-cols-2 gap-3 p-2 z-10"
style="-webkit-app-region: no-drag"
>
<button v-for="result in crunchySearchResults" @click="selectShow(result)" class="flex flex-row gap-3 px-3 py-3 hover:bg-[#747474] rounded-xl">
@ -61,10 +61,10 @@
</button>
</div>
</div>
<div v-if="isLoggedInCR && service === 'crunchyroll'" class="relative flex flex-col">
<div v-if="isLoggedInCR && service === 'crunchyroll' || isLoggedInADN && service === 'adn'" class="relative flex flex-col">
<input v-model="url" type="text" name="text" placeholder="URL" class="bg-[#5c5b5b] focus:outline-none px-3 py-2 rounded-xl text-sm text-center" />
</div>
<div v-if="isLoggedInCR && service === 'crunchyroll'" class="relative flex flex-col">
<div v-if="isLoggedInCR && service === 'crunchyroll' || isLoggedInADN && service === 'adn'" class="relative flex flex-col">
<input
@click="getFolderPath()"
v-model="path"
@ -80,6 +80,11 @@
class="bg-[#5c5b5b] focus:outline-none px-3 py-2 rounded-xl text-sm text-center cursor-pointer"
>Click to Login</button>
</div>
<div v-if="!isLoggedInADN && service === 'adn'" class="relative flex flex-col">
<button @click="openADNLogin"
class="bg-[#5c5b5b] focus:outline-none px-3 py-2 rounded-xl text-sm text-center cursor-pointer"
>Click to Login</button>
</div>
<div class="relative flex flex-col mt-auto">
<button @click="switchToSeason" class="relative py-3 border-2 rounded-xl flex flex-row items-center justify-center">
<div class="flex flex-row items-center justify-center transition-all" :class="isFetchingSeasons ? 'opacity-0' : 'opacity-100'">
@ -91,7 +96,6 @@
</div>
</button>
</div>
<!-- {{ searchresults }} -->
</div>
<div v-if="tab === 2" class="flex flex-col mt-5 gap-3.5 h-full" style="-webkit-app-region: no-drag">
<div class="relative flex flex-col">
@ -282,7 +286,7 @@ const searchActive = ref<boolean>(false)
const crunchySearchResults = ref<CrunchyrollSearchResults>()
const adnSearchResults = ref<ADNSearchResults>()
const CRselectedShow = ref<CrunchyrollSearchResult | null>()
const ADNselectedShow = ref<ADNSearchResult>()
const ADNselectedShow = ref<ADNSearchResult | null>()
const url = ref<string>('')
const path = ref<string>()
const service = ref<'adn' | 'crunchyroll'>('crunchyroll')
@ -302,7 +306,9 @@ const isFetchingEpisodes = ref<number>(0)
const isFetchingResults = ref<number>(0)
const isLoggedInCR = ref<boolean>(false)
let interval: NodeJS.Timeout;
const isLoggedInADN = ref<boolean>(false)
let intervalcr: NodeJS.Timeout;
let intervaladn: NodeJS.Timeout;
const checkIfLoggedInCR = async () => {
const { data, error } = await checkAccount('CR')
@ -312,8 +318,8 @@ const checkIfLoggedInCR = async () => {
return
}
if (interval) {
clearInterval(interval)
if (intervalcr) {
clearInterval(intervalcr)
}
isLoggedInCR.value = true
@ -328,10 +334,39 @@ const openCRLogin = () => {
backgroundColor: "#111111"
})
interval = setInterval(checkIfLoggedInCR, 1000)
intervalcr = setInterval(checkIfLoggedInCR, 1000)
}
const checkIfLoggedInADN = async () => {
const { data, error } = await checkAccount('ADN')
if (error.value) {
isLoggedInADN.value = false
return
}
if (intervaladn) {
clearInterval(intervaladn)
}
isLoggedInADN.value = true
}
const openADNLogin = () => {
(window as any).myAPI.openWindow({
title: "ADN Login",
url: isProduction ? 'http://localhost:8079/adnlogin' : 'http://localhost:3000/adnlogin',
width: 600,
height: 300,
backgroundColor: "#111111"
})
intervalcr = setInterval(checkIfLoggedInADN, 1000)
}
checkIfLoggedInCR()
checkIfLoggedInADN()
const fetchSearch = async () => {
if (!search.value || search.value.length === 0) {
@ -341,7 +376,9 @@ const fetchSearch = async () => {
return
}
isFetchingResults.value++
if (!isFetchingResults.value) {
isFetchingResults.value++
}
if (service.value === 'adn') {
adnSearchResults.value = await searchADN(search.value)
@ -351,7 +388,9 @@ const fetchSearch = async () => {
crunchySearchResults.value = await searchCrunchy(search.value)
}
isFetchingResults.value--
if (isFetchingResults.value) {
isFetchingResults.value--
}
searchActive.value = true
}
@ -367,6 +406,12 @@ const handleInputChange = () => {
debounceFetchSearch()
}
watch(url, () => {
if (url.value.length === 0 || !url.value) {
searchActive.value = false;
}
})
onMounted(() => {
;(window as any).myAPI.getFolder().then((result: any) => {
path.value = result
@ -396,12 +441,21 @@ const selectShow = async (show: any) => {
crunchySearchResults.value = []
adnSearchResults.value = []
searchActive.value = false
if (isFetchingResults.value) {
isFetchingResults.value--
}
}
watch(selectedSeason, () => {
refetchEpisodes()
})
watch(service, () => {
url.value = "",
CRselectedShow.value = null,
ADNselectedShow.value = null
})
watch(selectedStartEpisode, () => {
if (!selectedEndEpisode.value) return
if (!episodes.value) return

59
pages/adnlogin.vue Normal file
View File

@ -0,0 +1,59 @@
<template>
<div class="h-screen overflow-hidden bg-[#111111] flex flex-col p-5 text-white" style="-webkit-app-region: drag">
<div class="relative flex flex-row items-center justify-center">
<div class="text-2xl">ADN Login</div>
</div>
<div class="flex flex-col mt-5 gap-3.5 h-full" style="-webkit-app-region: no-drag">
<div class="relative flex flex-col">
<input v-model="username" type="text" name="text" placeholder="Email" class="bg-[#5c5b5b] focus:outline-none px-3 py-2 rounded-xl text-sm text-center" />
</div>
<div class="relative flex flex-col">
<input v-model="password" type="password" name="text" placeholder="Password" class="bg-[#5c5b5b] focus:outline-none px-3 py-2 rounded-xl text-sm text-center" />
</div>
</div>
<div class="relative flex flex-col mt-auto">
<button @click="login" class="relative py-3 border-2 rounded-xl flex flex-row items-center justify-center" style="-webkit-app-region: no-drag">
<div class="flex flex-row items-center justify-center transition-all" :class="isLoggingIn ? 'opacity-0' : 'opacity-100'">
<div class="text-xl">Login</div>
</div>
<div class="absolute flex flex-row items-center justify-center gap-1 transition-all" :class="isLoggingIn ? 'opacity-100' : 'opacity-0'">
<Icon name="mdi:loading" class="h-6 w-6 animate-spin" />
<div class="text-xl">Logging in</div>
</div>
</button>
</div>
</div>
</template>
<script lang="ts" setup>
import { loginAccount } from '~/components/Crunchyroll/Account'
const isProduction = process.env.NODE_ENV !== 'development'
const username = ref<string>()
const password = ref<string>()
const isLoggingIn = ref<number>(0)
const login = async () => {
isLoggingIn.value++
if (!username.value) {
isLoggingIn.value--
return
}
if (!password.value) {
isLoggingIn.value--
return
}
const { data, error } = await loginAccount(username.value, password.value, 'ADN')
if (error.value) {
isLoggingIn.value--
return
}
isLoggingIn.value--
close()
}
</script>
<style></style>

View File

@ -378,92 +378,74 @@ import { useFetch } from '../useFetch'
// }
// }
export async function adnyLogin(user: string, passw: string) {
const cachedData:
| {
access_token: string
refresh_token: string
expires_in: number
token_type: string
scope: string
country: string
account_id: string
profile_id: string
}
| undefined = server.CacheController.get('adntoken')
if (!cachedData) {
var { data, error } = await adnLoginFetch(user, passw)
if (error) {
messageBox(
'error',
['Cancel'],
2,
'Failed to login',
'Failed to login to ADN',
(error.error as string)
)
return { data: null, error: error.error }
export async function adnLogin(user: string, passw: string) {
const cachedData:
| {
access_token: string
refresh_token: string
expires_in: number
token_type: string
scope: string
country: string
account_id: string
profile_id: string
}
if (!data) {
messageBox('error', ['Cancel'], 2, 'Failed to login', 'Failed to login to ADN', 'ADN returned null')
return { data: null, error: 'ADN returned null' }
}
if (!data.access_token) {
messageBox('error', ['Cancel'], 2, 'Failed to login', 'Failed to login to ADN', 'ADN returned malformed data')
return { data: null, error: 'ADN returned malformed data' }
}
server.CacheController.set('adntoken', data, data.expires_in - 30)
return { data: data, error: null }
}
return { data: cachedData, error: null }
}
async function adnLoginFetch(user: string, passw: string) {
const headers = {
Authorization: 'Basic dC1rZGdwMmg4YzNqdWI4Zm4wZnE6eWZMRGZNZnJZdktYaDRKWFMxTEVJMmNDcXUxdjVXYW4=',
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'Crunchyroll/3.46.2 Android/13 okhttp/4.12.0'
}
const body: any = {
username: user,
password: passw,
grant_type: 'password',
scope: 'offline_access',
device_name: 'RMX2170',
device_type: 'realme RMX2170'
}
const { data, error } = await useFetch<{
access_token: string
refresh_token: string
expires_in: number
token_type: string
scope: string
country: string
account_id: string
profile_id: string
}>('https://beta-api.crunchyroll.com/auth/v1/token', {
type: 'POST',
body: new URLSearchParams(body).toString(),
header: headers,
credentials: 'same-origin'
})
| undefined = server.CacheController.get('adntoken')
if (!cachedData) {
var { data, error } = await adnLoginFetch(user, passw)
if (error) {
return { data: null, error: error }
messageBox('error', ['Cancel'], 2, 'Failed to login', 'Failed to login to ADN', error.error as string)
return { data: null, error: error.error }
}
if (!data) {
return { data: null, error: null }
messageBox('error', ['Cancel'], 2, 'Failed to login', 'Failed to login to ADN', 'ADN returned null')
return { data: null, error: 'ADN returned null' }
}
if (!data.accessToken) {
messageBox('error', ['Cancel'], 2, 'Failed to login', 'Failed to login to ADN', 'ADN returned malformed data')
return { data: null, error: 'ADN returned malformed data' }
}
server.CacheController.set('adntoken', data, 300)
return { data: data, error: null }
}
return { data: cachedData, error: null }
}
async function adnLoginFetch(user: string, passw: string) {
const headers = {
'x-target-distribution': 'de',
'Content-Type': 'application/json'
}
const body = {
username: user,
password: passw,
source: 'Web',
rememberMe: true
}
const { data, error } = await useFetch<{
accessToken: string;
}>('https://gw.api.animationdigitalnetwork.fr/authentication/login', {
type: 'POST',
body: JSON.stringify(body),
header: headers,
})
if (error) {
return { data: null, error: error }
}
if (!data) {
return { data: null, error: null }
}
return { data: data, error: null }
}

View File

@ -2,6 +2,7 @@ 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<{
Params: {
@ -48,9 +49,9 @@ export async function loginController(
}
if (params.id === 'ADN') {
// const { data, error } = await adnLogin(body.user, body.password)
// responseError = error,
// responseData = data
const { data, error } = await adnLogin(body.user, body.password)
responseError = error,
responseData = data
}
if (responseError || !responseData) {