2023-05-18 13:25:19 +02:00
/ *
* Copyright ( C ) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at https : //mozilla.org/MPL/2.0/.
* /
2023-06-04 00:30:48 +02:00
import { AxiosInstance , AxiosRequestConfig } from 'axios' ;
2023-06-08 13:40:50 +02:00
import useSWR , { Middleware , SWRConfiguration , SWRResponse } from 'swr' ;
2023-05-18 13:25:19 +02:00
import useSWRInfinite , { SWRInfiniteConfiguration , SWRInfiniteResponse } from 'swr/infinite' ;
2023-09-01 20:21:59 +02:00
import {
FetchResult ,
MutationHookOptions ,
MutationOptions ,
MutationTuple ,
QueryHookOptions ,
QueryResult ,
TypedDocumentNode ,
useMutation ,
useQuery ,
} from '@apollo/client' ;
import { OperationVariables } from '@apollo/client/core' ;
2023-09-08 00:06:24 +02:00
import { useState } from 'react' ;
2023-05-18 13:25:19 +02:00
import {
BackupValidationResult ,
ICategory ,
IChapter ,
IMangaChapter ,
ISourceFilters ,
PaginatedList ,
2023-05-20 13:12:23 +02:00
PaginatedMangaList ,
2023-05-18 13:25:19 +02:00
SourcePreferences ,
SourceSearchResult ,
2023-08-15 13:54:29 +02:00
} from '@/typings.ts' ;
2023-08-15 13:54:55 +02:00
import { HttpMethod as DefaultHttpMethod , IRestClient , RestClient } from '@/lib/requests/client/RestClient.ts' ;
2023-08-15 13:54:29 +02:00
import storage from '@/util/localStorage.tsx' ;
2023-09-01 20:21:59 +02:00
import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts' ;
2023-09-01 20:24:40 +02:00
import {
2023-09-01 20:39:30 +02:00
CategoryOrderBy ,
2023-09-01 20:26:06 +02:00
CheckForServerUpdatesQuery ,
CheckForServerUpdatesQueryVariables ,
2023-09-01 20:40:24 +02:00
ClearDownloaderMutation ,
ClearDownloaderMutationVariables ,
2023-09-01 20:39:30 +02:00
CreateCategoryInput ,
CreateCategoryMutation ,
CreateCategoryMutationVariables ,
DeleteCategoryMutation ,
DeleteCategoryMutationVariables ,
2023-09-01 20:36:40 +02:00
DeleteDownloadedChapterMutation ,
DeleteDownloadedChapterMutationVariables ,
DeleteDownloadedChaptersMutation ,
DeleteDownloadedChaptersMutationVariables ,
2023-09-01 20:40:24 +02:00
DequeueChapterDownloadMutation ,
DequeueChapterDownloadMutationVariables ,
DequeueChapterDownloadsMutation ,
DequeueChapterDownloadsMutationVariables ,
EnqueueChapterDownloadMutation ,
EnqueueChapterDownloadMutationVariables ,
EnqueueChapterDownloadsMutation ,
EnqueueChapterDownloadsMutationVariables ,
2023-09-08 00:06:24 +02:00
FetchSourceMangaInput ,
FetchSourceMangaType ,
FilterChangeInput ,
2023-09-01 20:25:46 +02:00
GetAboutQuery ,
GetAboutQueryVariables ,
2023-09-01 20:28:23 +02:00
GetExtensionsFetchMutation ,
GetExtensionsFetchMutationVariables ,
2023-09-01 20:39:30 +02:00
GetCategoriesQuery ,
GetCategoriesQueryVariables ,
2023-09-06 21:47:13 +02:00
GetCategoryMangasQuery ,
GetCategoryMangasQueryVariables ,
2023-09-01 20:28:23 +02:00
GetExtensionsQuery ,
GetExtensionsQueryVariables ,
2023-09-01 20:24:40 +02:00
GetGlobalMetadatasQuery ,
GetGlobalMetadatasQueryVariables ,
2023-09-08 00:44:01 +02:00
GetMangaFetchMutation ,
GetMangaFetchMutationVariables ,
GetMangaQuery ,
GetMangaQueryVariables ,
2023-09-08 00:06:24 +02:00
GetSourceMangasFetchMutation ,
GetSourceMangasFetchMutationVariables ,
2023-09-01 20:29:19 +02:00
GetSourceQuery ,
GetSourceQueryVariables ,
GetSourcesQuery ,
GetSourcesQueryVariables ,
2023-09-01 20:40:39 +02:00
GetUpdateStatusQuery ,
GetUpdateStatusQueryVariables ,
2023-09-01 20:28:23 +02:00
InstallExternalExtensionMutation ,
InstallExternalExtensionMutationVariables ,
2023-09-01 20:40:24 +02:00
ReorderChapterDownloadMutation ,
ReorderChapterDownloadMutationVariables ,
2023-09-01 20:39:30 +02:00
SetCategoryMetadataMutation ,
SetCategoryMetadataMutationVariables ,
2023-09-01 20:36:40 +02:00
SetChapterMetadataMutation ,
SetChapterMetadataMutationVariables ,
2023-09-01 20:24:40 +02:00
SetGlobalMetadataMutation ,
SetGlobalMetadataMutationVariables ,
2023-09-01 20:33:35 +02:00
SetMangaMetadataMutation ,
2023-09-01 20:40:24 +02:00
StartDownloaderMutation ,
StartDownloaderMutationVariables ,
StopDownloaderMutation ,
StopDownloaderMutationVariables ,
2023-09-01 20:40:39 +02:00
StopUpdaterMutation ,
StopUpdaterMutationVariables ,
UpdateCategoryMangasMutation ,
UpdateCategoryMangasMutationVariables ,
2023-09-01 20:39:30 +02:00
UpdateCategoryMutation ,
UpdateCategoryMutationVariables ,
UpdateCategoryOrderMutation ,
UpdateCategoryOrderMutationVariables ,
UpdateCategoryPatchInput ,
2023-09-01 20:36:40 +02:00
UpdateChapterMutation ,
UpdateChapterMutationVariables ,
UpdateChapterPatchInput ,
UpdateChaptersMutation ,
UpdateChaptersMutationVariables ,
2023-09-01 20:28:23 +02:00
UpdateExtensionMutation ,
UpdateExtensionMutationVariables ,
UpdateExtensionPatchInput ,
2023-09-01 20:40:39 +02:00
UpdateLibraryMangasMutation ,
UpdateLibraryMangasMutationVariables ,
2023-09-01 20:33:35 +02:00
UpdateMangaCategoriesMutation ,
UpdateMangaCategoriesMutationVariables ,
UpdateMangaMutation ,
UpdateMangaMutationVariables ,
UpdateMangaPatchInput ,
2023-09-01 20:24:40 +02:00
} from '@/lib/graphql/generated/graphql.ts' ;
import { GET_GLOBAL_METADATA , GET_GLOBAL_METADATAS } from '@/lib/graphql/queries/GlobalMetadataQuery.ts' ;
import { SET_GLOBAL_METADATA } from '@/lib/graphql/mutations/GlobalMetadataMutation.ts' ;
2023-09-01 20:26:06 +02:00
import { CHECK_FOR_SERVER_UPDATES , GET_ABOUT } from '@/lib/graphql/queries/ServerInfoQuery.ts' ;
2023-09-01 20:28:23 +02:00
import { GET_EXTENSION , GET_EXTENSIONS } from '@/lib/graphql/queries/ExtensionQuery.ts' ;
import {
GET_EXTENSIONS_FETCH ,
INSTALL_EXTERNAL_EXTENSION ,
UPDATE_EXTENSION ,
} from '@/lib/graphql/mutations/ExtensionMutation.ts' ;
2023-09-01 20:29:19 +02:00
import { GET_SOURCE , GET_SOURCES } from '@/lib/graphql/queries/SourceQuery.ts' ;
2023-09-08 00:44:01 +02:00
import {
GET_MANGA_FETCH ,
SET_MANGA_METADATA ,
UPDATE_MANGA ,
UPDATE_MANGA_CATEGORIES ,
} from '@/lib/graphql/mutations/MangaMutation.ts' ;
2023-09-01 20:33:35 +02:00
import { GET_MANGA , GET_MANGAS } from '@/lib/graphql/queries/MangaQuery.ts' ;
import { GET_CATEGORIES , GET_CATEGORY , GET_CATEGORY_MANGAS } from '@/lib/graphql/queries/CategoryQuery.ts' ;
import { GET_SOURCE_MANGAS_FETCH } from '@/lib/graphql/mutations/SourceMutation.ts' ;
2023-09-01 20:40:24 +02:00
import {
CLEAR_DOWNLOADER ,
DELETE_DOWNLOADED_CHAPTER ,
DELETE_DOWNLOADED_CHAPTERS ,
DEQUEUE_CHAPTER_DOWNLOAD ,
DEQUEUE_CHAPTER_DOWNLOADS ,
ENQUEUE_CHAPTER_DOWNLOAD ,
ENQUEUE_CHAPTER_DOWNLOADS ,
REORDER_CHAPTER_DOWNLOAD ,
START_DOWNLOADER ,
STOP_DOWNLOADER ,
} from '@/lib/graphql/mutations/DownloaderMutation.ts' ;
2023-09-01 20:36:40 +02:00
import { GET_CHAPTER , GET_CHAPTERS } from '@/lib/graphql/queries/ChapterQuery.ts' ;
import { SET_CHAPTER_METADATA , UPDATE_CHAPTER , UPDATE_CHAPTERS } from '@/lib/graphql/mutations/ChapterMutation.ts' ;
2023-09-01 20:39:30 +02:00
import {
CREATE_CATEGORY ,
DELETE_CATEGORY ,
SET_CATEGORY_METADATA ,
UPDATE_CATEGORY ,
UPDATE_CATEGORY_ORDER ,
} from '@/lib/graphql/mutations/CategoryMutation.ts' ;
2023-09-01 20:40:24 +02:00
import { GET_DOWNLOAD_STATUS } from '@/lib/graphql/queries/DownloaderQuery.ts' ;
2023-09-01 20:40:39 +02:00
import {
STOP_UPDATER ,
UPDATE_CATEGORY_MANGAS ,
UPDATE_LIBRARY_MANGAS ,
} from '@/lib/graphql/mutations/UpdaterMutation.ts' ;
import { GET_UPDATE_STATUS } from '@/lib/graphql/queries/UpdaterQuery.ts' ;
2023-05-18 13:25:19 +02:00
enum SWRHttpMethod {
SWR_GET ,
SWR_GET_INFINITE ,
SWR_POST ,
2023-05-22 14:04:05 +02:00
SWR_POST_INFINITE ,
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:21:59 +02:00
enum GQLMethod {
USE_QUERY = 'USE_QUERY' ,
USE_MUTATION = 'USE_MUTATION' ,
MUTATION = 'MUTATION' ,
}
2023-05-18 13:25:19 +02:00
type HttpMethodType = DefaultHttpMethod | SWRHttpMethod ;
const HttpMethod = { . . . SWRHttpMethod , . . . DefaultHttpMethod } ;
type RequestOption = { doOnlineFetch? : boolean } ;
type CustomSWROptions < Data > = {
skipRequest? : boolean ;
getEndpoint ? : ( index : number , previousData : Data | null ) = > string | null ;
2023-06-08 13:40:50 +02:00
disableCache? : boolean ;
2023-05-18 13:25:19 +02:00
} ;
type SWROptions < Data = any , Error = any > = SWRConfiguration < Data , Error > & CustomSWROptions < Data > ;
type SWRInfiniteOptions < Data = any , Error = any > = SWRInfiniteConfiguration < Data , Error > & CustomSWROptions < Data > ;
2023-05-28 02:18:23 +02:00
type SWRInfiniteResponseLoadInfo = {
isInitialLoad : boolean ;
isLoadMore : boolean ;
} ;
2023-05-23 13:27:38 +02:00
type AbortableRequest = { abortRequest : AbortController [ 'abort' ] } ;
2023-06-04 00:30:48 +02:00
export type AbortableAxiosResponse < Data = any > = { response : Promise < Data > } & AbortableRequest ;
2023-05-28 12:16:06 +02:00
export type AbortableSWRResponse < Data = any , Error = any > = SWRResponse < Data , Error > & AbortableRequest ;
export type AbortableSWRInfiniteResponse < Data = any , Error = any > = SWRInfiniteResponse < Data , Error > &
2023-05-28 02:18:23 +02:00
AbortableRequest &
SWRInfiniteResponseLoadInfo ;
2023-05-23 13:27:38 +02:00
2023-09-01 20:21:59 +02:00
type AbortableApolloUseQueryResponse <
Data = any ,
Variables extends OperationVariables = OperationVariables ,
> = QueryResult < Data , Variables > & AbortableRequest ;
type AbortableApolloUseMutationResponse < Data = any , Variables extends OperationVariables = OperationVariables > = [
MutationTuple < Data , Variables > [ 0 ] ,
MutationTuple < Data , Variables > [ 1 ] & AbortableRequest ,
] ;
2023-09-08 00:06:24 +02:00
type AbortableApolloUseMutationPaginatedResponse <
Data = any ,
Variables extends OperationVariables = OperationVariables ,
> = [
( page : number ) = > Promise < FetchResult < Data > > ,
( MutationTuple < Data , Variables > [ 1 ] & AbortableRequest & { size : number ; loadingMore : boolean } ) [ ] ,
] ;
2023-09-01 20:21:59 +02:00
type AbortableApolloMutationResponse < Data = any > = { response : Promise < FetchResult < Data > > } & AbortableRequest ;
2023-06-08 13:40:50 +02:00
const isLoadingMore = ( swrResult : SWRInfiniteResponse ) : boolean = > {
const isNextPageMissing = ! ! swrResult . data && typeof swrResult . data [ swrResult . size - 1 ] === 'undefined' ;
2023-06-16 00:14:22 +02:00
const isRequestActive = swrResult . isValidating ;
2023-06-08 13:40:50 +02:00
// SWR "isLoading" state is only updated for the first load, for every subsequent load it's "false"
2023-06-16 00:14:22 +02:00
return ! swrResult . isLoading && swrResult . size > 0 && isNextPageMissing && isRequestActive ;
2023-06-08 13:40:50 +02:00
} ;
const disableSwrInfiniteCache : Middleware = ( useSWRNext ) = > ( key , fetcher , config ) = > {
const swr = useSWRNext ( key , fetcher , config ) as unknown as SWRInfiniteResponse ;
const { size , data , isLoading , isValidating } = swr ;
const isActuallyValidating = ! isLoading && ! isLoadingMore ( swr ) && isValidating ;
return {
. . . swr ,
isLoading : isActuallyValidating ? true : isLoading ,
data : isActuallyValidating ? undefined : data ,
size : isActuallyValidating ? 1 : size ,
} as SWRResponse ;
} ;
const disableSwrCache : Middleware = ( useSWRNext ) = > ( key , fetcher , config ) = > {
const swr = useSWRNext ( key , fetcher , config ) ;
const { data , isLoading , isValidating } = swr ;
return { . . . swr , isLoading : isValidating ? true : isLoading , data : isValidating ? undefined : data } ;
} ;
2023-05-18 13:25:19 +02:00
// the following endpoints have not been implemented:
// - PUT /api/v1/manga/{mangaId}/chapter/{chapterIndex} - modify chapter # PATCH endpoint used instead
// - POST /api/v1/backup/import - import backup # "import backup file" endpoint used instead
// - POST /api/v1/backup/validate - validate backup # "validate backup file" endpoint used instead
// - GET /api/v1/backup/export - export backup # no function needed, url gets called via link triggering the download
export class RequestManager {
2023-06-04 00:50:58 +02:00
public static readonly API_VERSION = '/api/v1/' ;
2023-05-18 13:25:19 +02:00
2023-09-01 20:21:59 +02:00
private readonly graphQLClient = new GraphQLClient ( ) ;
2023-05-18 13:25:19 +02:00
private readonly restClient : RestClient = new RestClient ( ) ;
public getClient ( ) : IRestClient {
return this . restClient ;
}
2023-05-23 13:25:48 +02:00
public updateClient ( config : Partial < AxiosInstance [ 'defaults' ] > ) : void {
2023-05-18 13:25:19 +02:00
this . restClient . updateConfig ( config ) ;
2023-09-01 20:21:59 +02:00
this . graphQLClient . updateConfig ( { uri : config.baseURL } ) ;
2023-05-18 13:25:19 +02:00
}
public getBaseUrl ( ) : string {
return this . restClient . getClient ( ) . defaults . baseURL ! ;
}
public getWebSocketBaseUrl ( ) : string {
return this . getBaseUrl ( ) . replace ( 'http' , 'ws' ) ;
}
public getValidWebSocketUrl ( path : string , apiVersion = RequestManager . API_VERSION ) : string {
return ` ${ this . getWebSocketBaseUrl ( ) } ${ apiVersion } ${ path } ` ;
}
public getUpdateWebSocket ( ) : WebSocket {
return new WebSocket ( this . getValidWebSocketUrl ( 'update' ) ) ;
}
public getDownloadWebSocket ( ) : WebSocket {
return new WebSocket ( this . getValidWebSocketUrl ( 'downloads' ) ) ;
}
public getValidUrlFor ( endpoint : string , apiVersion : string = RequestManager . API_VERSION ) : string {
return ` ${ this . getBaseUrl ( ) } ${ apiVersion } ${ endpoint } ` ;
}
public getValidImgUrlFor ( imageUrl : string , apiVersion : string = '' ) : string {
const useCache = storage . getItem ( 'useCache' , true ) ;
const useCacheQuery = ` ?useCache= ${ useCache } ` ;
// server provided image urls already contain the api version
return ` ${ this . getValidUrlFor ( imageUrl , apiVersion ) } ${ useCacheQuery } ` ;
}
2023-09-01 20:21:59 +02:00
private doRequestNew < Data , Variables extends OperationVariables = OperationVariables > (
method : GQLMethod.USE_QUERY ,
operation : TypedDocumentNode < Data , Variables > ,
variables : Variables ,
options? : Partial < QueryHookOptions < Data , Variables > > ,
) : AbortableApolloUseQueryResponse < Data , Variables > ;
private doRequestNew < Data , Variables extends OperationVariables = OperationVariables > (
method : GQLMethod.USE_MUTATION ,
operation : TypedDocumentNode < Data , Variables > ,
variables : Variables | undefined ,
options? : Partial < MutationHookOptions < Data , Variables > > ,
) : AbortableApolloUseMutationResponse < Data , Variables > ;
private doRequestNew < Data , Variables extends OperationVariables = OperationVariables > (
method : GQLMethod.MUTATION ,
operation : TypedDocumentNode < Data , Variables > ,
variables : Variables ,
options? : Partial < MutationOptions < Data , Variables > > ,
) : AbortableApolloMutationResponse < Data > ;
private doRequestNew < Data , Variables extends OperationVariables = OperationVariables > (
method : GQLMethod ,
operation : TypedDocumentNode < Data , Variables > ,
variables : Variables ,
options ? :
| QueryHookOptions < Data , Variables >
| MutationHookOptions < Data , Variables >
| MutationOptions < Data , Variables > ,
) :
| AbortableApolloUseQueryResponse < Data , Variables >
| AbortableApolloUseMutationResponse < Data , Variables >
| AbortableApolloMutationResponse < Data > {
const abortController = new AbortController ( ) ;
const abortRequest = ( reason? : any ) : void = > {
if ( ! abortController . signal . aborted ) {
abortController . abort ( reason ) ;
}
} ;
switch ( method ) {
case GQLMethod . USE_QUERY :
return {
. . . useQuery < Data , Variables > ( operation , {
variables ,
client : this.graphQLClient.client ,
. . . options ,
context : {
. . . options ? . context ,
fetchOptions : {
signal : abortController.signal ,
. . . options ? . context ? . fetchOptions ,
} ,
} ,
} ) ,
abortRequest ,
} ;
case GQLMethod . USE_MUTATION :
// eslint-disable-next-line no-case-declarations
const mutationResult = useMutation < Data , Variables > ( operation , {
variables ,
client : this.graphQLClient.client ,
. . . ( options as MutationHookOptions < Data , Variables > ) ,
context : {
. . . options ? . context ,
fetchOptions : {
signal : abortController.signal ,
. . . options ? . context ? . fetchOptions ,
} ,
} ,
} ) ;
return [ mutationResult [ 0 ] , { . . . mutationResult [ 1 ] , abortRequest } ] ;
case GQLMethod . MUTATION :
return {
response : this.graphQLClient.client.mutate < Data , Variables > ( {
mutation : operation ,
variables ,
. . . ( options as MutationOptions < Data , Variables > ) ,
context : {
. . . options ? . context ,
fetchOptions : {
signal : abortController.signal ,
. . . options ? . context ? . fetchOptions ,
} ,
} ,
} ) ,
abortRequest ,
} ;
default :
throw new Error ( ` unexpected GQLRequest type " ${ method } " ` ) ;
}
}
2023-05-18 13:25:19 +02:00
private useSwr <
Data = any ,
ErrorResponse = any ,
OptionsSWR extends SWROptions < Data , ErrorResponse > = SWROptions < Data , ErrorResponse > ,
> (
url : string ,
httpMethod : DefaultHttpMethod ,
{
data ,
axiosOptions ,
swrOptions ,
} : {
data? : Data ;
axiosOptions? : AxiosRequestConfig ;
swrOptions? : OptionsSWR ;
} = { } ,
) : SWRResponse < Data , ErrorResponse > {
2023-06-08 13:40:50 +02:00
const { skipRequest , disableCache , . . . swrConfig } = swrOptions ? ? { } ;
2023-05-18 13:25:19 +02:00
// in case "null" gets passed as the url, SWR won't do the request
return useSWR ( skipRequest ? null : url , {
fetcher : ( path : string ) = > this . restClient . fetcher ( path , { data , httpMethod , config : axiosOptions } ) ,
2023-06-08 13:40:50 +02:00
use : disableCache ? [ disableSwrCache ] : undefined ,
2023-05-18 13:25:19 +02:00
. . . swrConfig ,
} ) ;
}
2023-05-20 13:12:23 +02:00
public useSwrInfinite <
Data = any ,
ErrorResponse = any ,
OptionsSWR extends SWRInfiniteOptions < Data , ErrorResponse > = SWRInfiniteOptions < Data , ErrorResponse > ,
> (
2023-05-18 13:25:19 +02:00
getEndpoint : Required < CustomSWROptions < Data > > [ 'getEndpoint' ] ,
2023-05-22 14:04:05 +02:00
httpMethod : DefaultHttpMethod ,
{
data ,
axiosOptions ,
swrOptions ,
} : { data? : any ; axiosOptions? : AxiosRequestConfig ; swrOptions? : OptionsSWR } = { } ,
2023-05-28 02:18:23 +02:00
) : SWRInfiniteResponse < Data , ErrorResponse > & SWRInfiniteResponseLoadInfo {
2023-06-08 13:40:50 +02:00
const { skipRequest , disableCache , . . . swrConfig } = swrOptions ? ? { } ;
2023-05-20 13:12:23 +02:00
2023-05-18 13:25:19 +02:00
// useSWRInfinite will (by default) revalidate the first page, to check if the other pages have to be revalidated as well
2023-05-28 02:18:23 +02:00
const swrResult = useSWRInfinite < Data , ErrorResponse > (
2023-05-18 13:25:19 +02:00
( index , previousData ) = > {
const pageEndpoint = getEndpoint ( index , previousData ) ;
2023-05-20 13:12:23 +02:00
return pageEndpoint !== null && ! skipRequest ? this . getValidUrlFor ( pageEndpoint ) : null ;
2023-05-18 13:25:19 +02:00
} ,
{
2023-05-22 14:04:05 +02:00
fetcher : ( path : string ) = > this . restClient . fetcher ( path , { httpMethod , data , config : axiosOptions } ) ,
2023-06-08 13:40:50 +02:00
use : disableCache ? [ disableSwrInfiniteCache ] : undefined ,
2023-05-20 13:12:23 +02:00
. . . swrConfig ,
2023-05-18 13:25:19 +02:00
} ,
) ;
2023-05-28 02:18:23 +02:00
const customSwrResult = {
. . . swrResult ,
isInitialLoad : swrResult.isLoading ,
2023-06-08 13:40:50 +02:00
isLoadMore : isLoadingMore ( swrResult ) ,
2023-05-18 13:25:19 +02:00
} ;
2023-05-28 02:18:23 +02:00
customSwrResult . isLoading = customSwrResult . isInitialLoad || customSwrResult . isLoadMore ;
return customSwrResult ;
2023-05-18 13:25:19 +02:00
}
/ * *
* Performs the actual server request .
*
* In case { @link HttpMethod . GET_SWR } gets passed , the "useSWR" hook gets called .
* In case { @link HttpMethod . GET_SWR_INFINITE } gets passed , the "useSWRInfinite" hook gets called .
* In that case "getEndpoint" has to be passed , which gets used over "endpoint"
*
* Pass "skipRequest" to make SWR skip sending the request to the server .
* In case "formData" is passed , "data" gets ignored .
* /
private doRequest <
2023-05-23 13:27:38 +02:00
Result extends AbortableAxiosResponse | AbortableSWRResponse | AbortableSWRInfiniteResponse ,
2023-05-18 13:25:19 +02:00
OptionsSWR extends SWROptions | SWRInfiniteOptions ,
> (
httpMethod : HttpMethodType ,
endpoint : string ,
{
apiVersion = RequestManager . API_VERSION ,
data : dataToSend ,
formData ,
axiosOptions ,
swrOptions ,
} : {
apiVersion? : string ;
data? : any ;
formData ? : { [ key : string ] : any } ;
axiosOptions? : AxiosRequestConfig ;
swrOptions? : OptionsSWR ;
} = { } ,
) : Result {
const url = ` ${ apiVersion } ${ endpoint } ` ;
let data = dataToSend ;
if ( formData ) {
data = new FormData ( ) ;
Object . entries ( formData ) . forEach ( ( [ key , value ] ) = > {
2023-06-04 00:32:08 +02:00
if ( value !== undefined ) data . append ( key , value ) ; // "append" automatically converts non string or blob values to strings
2023-05-18 13:25:19 +02:00
} ) ;
}
2023-05-23 13:27:38 +02:00
const abortController = new AbortController ( ) ;
const abortRequest = ( reason? : any ) : void = > {
if ( ! abortController . signal . aborted ) {
abortController . abort ( reason ) ;
}
} ;
const axiosOptionsWithAbortController = { . . . axiosOptions , signal : abortController.signal } ;
2023-05-18 13:25:19 +02:00
switch ( httpMethod ) {
case HttpMethod . SWR_GET :
2023-05-23 13:27:38 +02:00
return {
. . . ( this . useSwr ( url , HttpMethod . GET , { axiosOptions , swrOptions } ) as Result ) ,
abortRequest ,
} ;
2023-05-18 13:25:19 +02:00
case HttpMethod . SWR_GET_INFINITE :
// throw TypeError in case options aren't correctly passed
2023-05-23 13:27:38 +02:00
return {
. . . ( this . useSwrInfinite ( swrOptions ! . getEndpoint ! , HttpMethod . GET , {
axiosOptions : axiosOptionsWithAbortController ,
swrOptions ,
} ) as Result ) ,
abortRequest ,
} ;
2023-05-22 14:04:05 +02:00
case SWRHttpMethod . SWR_POST_INFINITE :
2023-05-23 13:27:38 +02:00
return {
. . . ( this . useSwrInfinite ( swrOptions ! . getEndpoint ! , HttpMethod . POST , {
data ,
axiosOptions : axiosOptionsWithAbortController ,
swrOptions ,
} ) as Result ) ,
abortRequest ,
} ;
2023-05-18 13:25:19 +02:00
case HttpMethod . SWR_POST :
2023-05-23 13:27:38 +02:00
return {
. . . ( this . useSwr ( url , HttpMethod . POST , {
data ,
axiosOptions : axiosOptionsWithAbortController ,
swrOptions ,
} ) as Result ) ,
controller : abortController ,
} ;
2023-05-18 13:25:19 +02:00
default :
2023-05-23 13:27:38 +02:00
return {
response : this.restClient.fetcher ( url , {
data ,
httpMethod ,
config : axiosOptionsWithAbortController ,
checkResponseIsJson : false ,
} ) ,
abortRequest ,
} as Result ;
2023-05-18 13:25:19 +02:00
}
}
2023-09-01 20:24:40 +02:00
public useGetGlobalMeta (
options? : QueryHookOptions < GetGlobalMetadatasQuery , GetGlobalMetadatasQueryVariables > ,
) : AbortableApolloUseQueryResponse < GetGlobalMetadatasQuery , GetGlobalMetadatasQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_GLOBAL_METADATAS , { } , options ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:24:40 +02:00
public setGlobalMetadata ( key : string , value : any ) : AbortableApolloMutationResponse < SetGlobalMetadataMutation > {
return this . doRequestNew < SetGlobalMetadataMutation , SetGlobalMetadataMutationVariables > (
GQLMethod . MUTATION ,
SET_GLOBAL_METADATA ,
{ input : { meta : { key , value : ` ${ value } ` } } } ,
{ refetchQueries : [ GET_GLOBAL_METADATA , GET_GLOBAL_METADATAS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:25:46 +02:00
public useGetAbout (
options? : QueryHookOptions < GetAboutQuery , GetAboutQueryVariables > ,
) : AbortableApolloUseQueryResponse < GetAboutQuery , GetAboutQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_ABOUT , { } , options ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:26:06 +02:00
public useCheckForUpdate (
options? : QueryHookOptions < CheckForServerUpdatesQuery , CheckForServerUpdatesQueryVariables > ,
) : AbortableApolloUseQueryResponse < CheckForServerUpdatesQuery , CheckForServerUpdatesQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , CHECK_FOR_SERVER_UPDATES , { } , options ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:28:23 +02:00
public useGetExtensionList (
options? : QueryHookOptions < GetExtensionsQuery , GetExtensionsQueryVariables > ,
) : AbortableApolloUseQueryResponse < GetExtensionsQuery , GetExtensionsQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_EXTENSIONS , { } , options ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:28:23 +02:00
public useExtensionListFetch (
options? : MutationHookOptions < GetExtensionsFetchMutation , GetExtensionsFetchMutationVariables > ,
) : AbortableApolloUseMutationResponse < GetExtensionsFetchMutation , GetExtensionsFetchMutationVariables > {
return this . doRequestNew ( GQLMethod . USE_MUTATION , GET_EXTENSIONS_FETCH , { } , options ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:28:23 +02:00
public installExternalExtension (
extensionFile : File ,
) : AbortableApolloMutationResponse < InstallExternalExtensionMutation > {
return this . doRequestNew < InstallExternalExtensionMutation , InstallExternalExtensionMutationVariables > (
GQLMethod . MUTATION ,
INSTALL_EXTERNAL_EXTENSION ,
{ file : extensionFile } ,
{ refetchQueries : [ GET_EXTENSION , GET_EXTENSIONS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:28:23 +02:00
public updateExtension (
id : string ,
patch : UpdateExtensionPatchInput ,
) : AbortableApolloMutationResponse < UpdateExtensionMutation > {
return this . doRequestNew < UpdateExtensionMutation , UpdateExtensionMutationVariables > (
GQLMethod . MUTATION ,
UPDATE_EXTENSION ,
{ input : { id , patch } } ,
{ refetchQueries : [ GET_EXTENSION , GET_EXTENSIONS , GET_SOURCES ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
public getExtensionIconUrl ( extension : string ) : string {
return this . getValidImgUrlFor ( ` extension/icon/ ${ extension } ` ) ;
}
2023-09-01 20:29:19 +02:00
public useGetSourceList (
options? : QueryHookOptions < GetSourcesQuery , GetSourcesQueryVariables > ,
) : AbortableApolloUseQueryResponse < GetSourcesQuery , GetSourcesQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_SOURCES , { } , options ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:29:19 +02:00
public useGetSource (
id : string ,
options? : QueryHookOptions < GetSourceQuery , GetSourceQueryVariables > ,
) : AbortableApolloUseQueryResponse < GetSourceQuery , GetSourceQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_SOURCE , { id } , options ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-08 00:06:24 +02:00
public useGetSourceMangas (
input : FetchSourceMangaInput ,
options? : MutationHookOptions < GetSourceMangasFetchMutation , GetSourceMangasFetchMutationVariables > ,
) : AbortableApolloUseMutationPaginatedResponse <
GetSourceMangasFetchMutation ,
GetSourceMangasFetchMutationVariables
> {
const createPaginatedResult = (
result : AbortableApolloUseMutationResponse [ 1 ] ,
page : number ,
) : AbortableApolloUseMutationPaginatedResponse [ 1 ] [ number ] = > {
const loading = result . loading || ! result . called ;
return {
. . . result ,
loading ,
size : page ,
loadingMore : loading && page > 1 ,
} ;
} ;
// TODO - implement caching
// - ? global cache with revalidating (same as SWR does, revalidate each page starting with 1st until the first page is reached whose data didn't change)
// - ? saving fetched mangas in location state and only "cache" when navigating prev/next
const [ mutate , result ] = this . doRequestNew < GetSourceMangasFetchMutation , GetSourceMangasFetchMutationVariables > (
GQLMethod . USE_MUTATION ,
GET_SOURCE_MANGAS_FETCH ,
{ input } ,
options ,
) ;
const [ previousResults , setPreviousResults ] = useState < AbortableApolloUseMutationPaginatedResponse [ 1 ] > ( [
createPaginatedResult ( result , input . page ) ,
] ) ;
const [ contentType , setContentType ] = useState ( input . type ) ;
const [ query , setQuery ] = useState ( input . query ) ;
const [ page , setPage ] = useState ( input . page ) ;
const paginatedResult = createPaginatedResult ( result , page ) ;
// TODO - option "global cache with revalidating"
// replace previousResults with cache
// cache specific response
// cache "base" key to specific page keys to be able to retrieve all necessary cached pages
// get cached results
// revalidate in background - revalidate first page -> result changed? revalidate every page until cached result and response is the same
// wrap "mutate" function to align with the expected type, which allows only passing a "page" argument
const wrappedMutate = ( newPage : number ) = > {
const resetPreviousResultForInitialLoad = newPage < page ;
if ( resetPreviousResultForInitialLoad ) {
setPreviousResults ( previousResults . filter ( ( prevResult ) = > prevResult . size <= newPage ) ) ;
}
if ( newPage !== page ) {
setPage ( newPage ) ;
}
return mutate ( {
variables : {
input : {
. . . input ,
page : newPage ,
} ,
} ,
} ) ;
} ;
const contentTypeChanged = contentType !== input . type ;
const queryChanged = query !== input . query ;
// instantly return empty results in case the provided variables changed - wait until the hook returns empty data,
// otherwise, updating the previous results will revert the reset
const resetPreviousResult = ( queryChanged || contentTypeChanged ) && ! paginatedResult . data ;
let updatedResults = [
. . . ( resetPreviousResult ? [ { . . . paginatedResult , size : page , loadingMore : false } ] : previousResults ) ,
] ;
if ( resetPreviousResult ) {
setContentType ( input . type ) ;
setQuery ( input . query ) ;
setPreviousResults ( [ paginatedResult ] ) ;
}
const resultChanged = previousResults [ page - 1 ] ? . loading !== paginatedResult . loading ;
const updatePreviousResult = resultChanged && ! resetPreviousResult ;
if ( updatePreviousResult ) {
updatedResults = [ . . . previousResults . slice ( 0 , page - 1 ) , paginatedResult ] ;
setPreviousResults ( updatedResults ) ;
}
return [ wrappedMutate , updatedResult ] ;
}
2023-05-18 13:25:19 +02:00
public useGetSourcePopularMangas (
sourceId : string ,
initialPages? : number ,
2023-05-20 13:12:23 +02:00
swrOptions? : SWRInfiniteOptions < PaginatedMangaList > ,
2023-05-23 13:27:38 +02:00
) : AbortableSWRInfiniteResponse < PaginatedMangaList > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( SWRHttpMethod . SWR_GET_INFINITE , '' , {
swrOptions : {
getEndpoint : ( page , previousData ) = >
2023-05-20 13:12:23 +02:00
previousData ? . hasNextPage ? ? true ? ` source/ ${ sourceId } /popular/ ${ page + 1 } ` : null ,
2023-05-18 13:25:19 +02:00
initialSize : initialPages ,
. . . swrOptions ,
} as typeof swrOptions ,
} ) ;
}
public useGetSourceLatestMangas (
sourceId : string ,
initialPages? : number ,
2023-05-20 13:12:23 +02:00
swrOptions? : SWRInfiniteOptions < PaginatedMangaList > ,
2023-05-23 13:27:38 +02:00
) : AbortableSWRInfiniteResponse < PaginatedMangaList > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( SWRHttpMethod . SWR_GET_INFINITE , '' , {
swrOptions : {
getEndpoint : ( page , previousData ) = >
2023-05-20 13:12:23 +02:00
previousData ? . hasNextPage ? ? true ? ` source/ ${ sourceId } /latest/ ${ page + 1 } ` : null ,
2023-05-18 13:25:19 +02:00
initialSize : initialPages ,
. . . swrOptions ,
} as typeof swrOptions ,
} ) ;
}
public useGetSourcePreferences (
sourceId : string ,
swrOptions? : SWROptions < SourcePreferences [ ] > ,
2023-05-23 13:27:38 +02:00
) : AbortableSWRResponse < SourcePreferences [ ] > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_GET , ` source/ ${ sourceId } /preferences ` , { swrOptions } ) ;
}
2023-05-23 13:27:38 +02:00
public setSourcePreferences ( sourceId : string , position : number , value : string ) : AbortableAxiosResponse {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . POST , ` source/ ${ sourceId } /preferences ` , { data : { position , value } } ) ;
}
public useGetSourceFilters (
sourceId : string ,
reset? : boolean ,
swrOptions? : SWROptions < ISourceFilters [ ] > ,
2023-05-23 13:27:38 +02:00
) : AbortableSWRResponse < ISourceFilters [ ] > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_GET , ` source/ ${ sourceId } /filters ` , { swrOptions } ) ;
}
2023-05-23 13:27:38 +02:00
public setSourceFilters ( sourceId : string , filters : { position : number ; state : string } [ ] ) : AbortableAxiosResponse {
2023-05-22 14:03:50 +02:00
return this . doRequest ( HttpMethod . POST , ` source/ ${ sourceId } /filters ` , { data : filters } ) ;
2023-05-18 13:25:19 +02:00
}
2023-05-23 13:27:38 +02:00
public resetSourceFilters ( sourceId : string ) : AbortableAxiosResponse {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . GET , ` source/ ${ sourceId } /filters?reset=true ` ) ;
}
public useSourceSearch (
2023-09-08 00:06:24 +02:00
source : string ,
query : string ,
filters? : FilterChangeInput [ ] ,
options? : MutationHookOptions < GetSourceMangasFetchMutation , GetSourceMangasFetchMutationVariables > ,
) : AbortableApolloUseMutationPaginatedResponse <
GetSourceMangasFetchMutation ,
GetSourceMangasFetchMutationVariables
> {
return this . useGetSourceMangas ( { type : FetchSourceMangaType . Search , source , query , filters , page : 1 } , options ) ;
2023-05-18 13:25:19 +02:00
}
public useSourceQuickSearch (
sourceId : string ,
searchTerm : string ,
filters : { position : number ; state : string } [ ] ,
initialPages? : number ,
swrOptions? : SWRInfiniteOptions < SourceSearchResult > ,
2023-05-23 13:27:38 +02:00
) : AbortableSWRInfiniteResponse < SourceSearchResult > {
2023-05-22 14:04:05 +02:00
return this . doRequest ( HttpMethod . SWR_POST_INFINITE , '' , {
data : { searchTerm , filter : filters } ,
2023-05-18 13:25:19 +02:00
swrOptions : {
getEndpoint : ( page , previousData ) = >
2023-05-20 13:12:23 +02:00
previousData ? . hasNextPage ? ? true
? ` source/ ${ sourceId } /quick-search?searchTerm= ${ searchTerm } &pageNum= ${ page + 1 } `
2023-05-18 13:25:19 +02:00
: null ,
initialSize : initialPages ,
. . . swrOptions ,
} as typeof swrOptions ,
} ) ;
}
public useGetManga (
mangaId : number | string ,
2023-09-08 00:44:01 +02:00
options? : QueryHookOptions < GetMangaQuery , GetMangaQueryVariables > ,
) : AbortableApolloUseQueryResponse < GetMangaQuery , GetMangaQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_MANGA , { id : Number ( mangaId ) } , options ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-08 00:44:01 +02:00
public getMangaFetch (
2023-05-18 13:25:19 +02:00
mangaId : number | string ,
2023-09-08 00:44:01 +02:00
options? : MutationOptions < GetMangaFetchMutation , GetMangaFetchMutationVariables > ,
) : AbortableApolloMutationResponse < GetMangaFetchMutation > {
return this . doRequestNew < GetMangaFetchMutation , GetMangaFetchMutationVariables > (
GQLMethod . MUTATION ,
GET_MANGA_FETCH ,
{
input : {
id : Number ( mangaId ) ,
} ,
} ,
{
refetchQueries : [ GET_MANGA , GET_MANGAS ] ,
. . . options ,
} ,
) ;
2023-05-18 13:25:19 +02:00
}
public getMangaThumbnailUrl ( mangaId : number ) : string {
return this . getValidImgUrlFor ( ` manga/ ${ mangaId } /thumbnail ` ) ;
}
2023-05-23 13:27:38 +02:00
public useGetMangaCategories (
mangaId : number ,
swrOptions? : SWROptions < ICategory [ ] > ,
) : AbortableSWRResponse < ICategory [ ] > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_GET , ` manga/ ${ mangaId } /category ` , { swrOptions } ) ;
}
2023-09-01 20:33:35 +02:00
public useUpdateMangaCategories (
options? : MutationHookOptions < UpdateMangaCategoriesMutation , UpdateMangaCategoriesMutationVariables > ,
) : AbortableApolloUseMutationResponse < UpdateMangaCategoriesMutation , UpdateMangaCategoriesMutationVariables > {
return this . doRequestNew ( GQLMethod . USE_MUTATION , UPDATE_MANGA_CATEGORIES , undefined , {
refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY , GET_CATEGORIES , GET_CATEGORY_MANGAS ] ,
. . . options ,
} ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:33:35 +02:00
public updateManga (
id : number ,
patch : UpdateMangaPatchInput ,
options? : MutationHookOptions < UpdateMangaMutation , UpdateMangaMutationVariables > ,
) : AbortableApolloMutationResponse < UpdateMangaMutation > {
return this . doRequestNew < UpdateMangaMutation , UpdateMangaMutationVariables > (
GQLMethod . MUTATION ,
UPDATE_MANGA ,
{ input : { id , patch } } ,
{
refetchQueries : [
GET_MANGA ,
GET_MANGAS ,
GET_CATEGORY_MANGAS ,
GET_CATEGORY ,
GET_CATEGORIES ,
GET_SOURCE_MANGAS_FETCH ,
] ,
. . . options ,
} ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:33:35 +02:00
public setMangaMeta (
mangaId : number ,
key : string ,
value : any ,
) : AbortableApolloMutationResponse < SetMangaMetadataMutation > {
return this . doRequestNew (
GQLMethod . MUTATION ,
SET_MANGA_METADATA ,
{
input : { meta : { mangaId , key , value : ` ${ value } ` } } ,
} ,
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY_MANGAS , GET_SOURCE_MANGAS_FETCH ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
public useGetMangaChapters (
mangaId : number | string ,
{ doOnlineFetch , . . . swrOptions } : SWROptions < IChapter [ ] > & RequestOption = { } ,
2023-05-23 13:27:38 +02:00
) : AbortableSWRResponse < IChapter [ ] > {
2023-05-18 13:25:19 +02:00
const onlineFetch = doOnlineFetch ? '?onlineFetch=true' : '' ;
return this . doRequest ( HttpMethod . SWR_GET , ` manga/ ${ mangaId } /chapters ${ onlineFetch } ` , {
swrOptions ,
} ) ;
}
2023-06-04 00:50:58 +02:00
public getMangaChapters ( mangaId : number | string , doOnlineFetch? : boolean ) : AbortableAxiosResponse < IChapter [ ] > {
const onlineFetch = doOnlineFetch ? '?onlineFetch=true' : '' ;
return this . doRequest ( HttpMethod . GET , ` manga/ ${ mangaId } /chapters ${ onlineFetch } ` ) ;
}
2023-05-18 13:25:19 +02:00
public useGetChapter (
mangaId : number | string ,
chapterIndex : number | string ,
swrOptions? : SWROptions < IChapter > ,
2023-05-23 13:27:38 +02:00
) : AbortableSWRResponse < IChapter > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_GET , ` manga/ ${ mangaId } /chapter/ ${ chapterIndex } ` , {
swrOptions ,
} ) ;
}
2023-06-04 00:50:58 +02:00
public getChapter ( mangaId : number | string , chapterIndex : number | string ) : AbortableAxiosResponse < IChapter > {
return this . doRequest ( HttpMethod . GET , ` manga/ ${ mangaId } /chapter/ ${ chapterIndex } ` ) ;
}
2023-09-01 20:36:40 +02:00
public deleteDownloadedChapter ( id : number ) : AbortableApolloMutationResponse < DeleteDownloadedChapterMutation > {
return this . doRequestNew < DeleteDownloadedChapterMutation , DeleteDownloadedChapterMutationVariables > (
GQLMethod . MUTATION ,
DELETE_DOWNLOADED_CHAPTER ,
{ input : { id } } ,
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY_MANGAS , GET_CHAPTERS ] } ,
) ;
}
public deleteDownloadedChapters ( ids : number [ ] ) : AbortableApolloMutationResponse < DeleteDownloadedChaptersMutation > {
return this . doRequestNew < DeleteDownloadedChaptersMutation , DeleteDownloadedChaptersMutationVariables > (
GQLMethod . MUTATION ,
DELETE_DOWNLOADED_CHAPTERS ,
{ input : { ids } } ,
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY_MANGAS , GET_CHAPTERS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
public updateChapter (
2023-09-01 20:36:40 +02:00
id : number ,
patch : UpdateChapterPatchInput ,
) : AbortableApolloMutationResponse < UpdateChapterMutation > {
return this . doRequestNew < UpdateChapterMutation , UpdateChapterMutationVariables > (
GQLMethod . MUTATION ,
UPDATE_CHAPTER ,
{ input : { id , patch } } ,
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY_MANGAS , GET_CHAPTER , GET_CHAPTERS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
public setChapterMeta (
2023-09-01 20:36:40 +02:00
chapterId : number ,
2023-05-18 13:25:19 +02:00
key : string ,
value : any ,
2023-09-01 20:36:40 +02:00
) : AbortableApolloMutationResponse < SetChapterMetadataMutation > {
return this . doRequestNew < SetChapterMetadataMutation , SetChapterMetadataMutationVariables > (
GQLMethod . MUTATION ,
SET_CHAPTER_METADATA ,
{ input : { meta : { chapterId , key , value : ` ${ value } ` } } } ,
{ refetchQueries : [ GET_CHAPTER , GET_CHAPTERS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
public getChapterPageUrl ( mangaId : number | string , chapterIndex : number | string , page : number ) : string {
return this . getValidImgUrlFor (
` manga/ ${ mangaId } /chapter/ ${ chapterIndex } /page/ ${ page } ` ,
RequestManager . API_VERSION ,
) ;
}
2023-09-01 20:36:40 +02:00
public updateChapters (
ids : number [ ] ,
patch : UpdateChapterPatchInput ,
) : AbortableApolloMutationResponse < UpdateChaptersMutation > {
return this . doRequestNew < UpdateChaptersMutation , UpdateChaptersMutationVariables > (
GQLMethod . MUTATION ,
UPDATE_CHAPTERS ,
{ input : { ids , patch } } ,
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY_MANGAS , GET_CHAPTER , GET_CHAPTERS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:39:30 +02:00
public useGetCategories ( ) : AbortableApolloUseQueryResponse < GetCategoriesQuery , GetCategoriesQueryVariables > {
return this . doRequestNew < GetCategoriesQuery , GetCategoriesQueryVariables > ( GQLMethod . USE_QUERY , GET_CATEGORIES , {
orderBy : CategoryOrderBy.Order ,
} ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:39:30 +02:00
public createCategory ( input : CreateCategoryInput ) : AbortableApolloMutationResponse < CreateCategoryMutation > {
return this . doRequestNew < CreateCategoryMutation , CreateCategoryMutationVariables > (
GQLMethod . MUTATION ,
CREATE_CATEGORY ,
{ input } ,
{ refetchQueries : [ GET_CATEGORIES ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:39:30 +02:00
public reorderCategory ( id : number , position : number ) : AbortableApolloMutationResponse < UpdateCategoryOrderMutation > {
return this . doRequestNew < UpdateCategoryOrderMutation , UpdateCategoryOrderMutationVariables > (
GQLMethod . MUTATION ,
UPDATE_CATEGORY_ORDER ,
{ input : { id , position } } ,
{ refetchQueries : [ GET_CATEGORIES ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-06 21:47:13 +02:00
public useGetCategoryMangas (
id : number ,
options? : QueryHookOptions < GetCategoryMangasQuery , GetCategoryMangasQueryVariables > ,
) : AbortableApolloUseQueryResponse < GetCategoryMangasQuery , GetCategoryMangasQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_CATEGORY_MANGAS , { id } , options ) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:39:30 +02:00
public deleteCategory ( categoryId : number ) : AbortableApolloMutationResponse < DeleteCategoryMutation > {
return this . doRequestNew < DeleteCategoryMutation , DeleteCategoryMutationVariables > (
GQLMethod . MUTATION ,
DELETE_CATEGORY ,
{ input : { categoryId } } ,
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORIES ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
public updateCategory (
2023-09-01 20:39:30 +02:00
id : number ,
patch : UpdateCategoryPatchInput ,
) : AbortableApolloMutationResponse < UpdateCategoryMutation > {
return this . doRequestNew < UpdateCategoryMutation , UpdateCategoryMutationVariables > (
GQLMethod . MUTATION ,
UPDATE_CATEGORY ,
{ input : { id , patch } } ,
{ refetchQueries : [ GET_CATEGORY , GET_CATEGORIES ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:39:30 +02:00
public setCategoryMeta (
categoryId : number ,
key : string ,
value : any ,
) : AbortableApolloMutationResponse < SetCategoryMetadataMutation > {
return this . doRequestNew < SetCategoryMetadataMutation , SetCategoryMetadataMutationVariables > (
GQLMethod . MUTATION ,
SET_CATEGORY_METADATA ,
{ input : { meta : { categoryId , key , value : ` ${ value } ` } } } ,
{ refetchQueries : [ GET_MANGA , GET_MANGAS , GET_CATEGORY , GET_CATEGORIES ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-05-23 13:27:38 +02:00
public restoreBackupFile ( file : File ) : AbortableAxiosResponse {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . POST , 'backup/import/file' , { formData : { 'backup.proto.gz' : file } } ) ;
}
public useValidateBackupFile (
file : File ,
swrOptions? : SWROptions < BackupValidationResult > ,
2023-05-23 13:27:38 +02:00
) : AbortableSWRResponse < BackupValidationResult > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_POST , 'backup/validate/file' , {
formData : { 'backup.proto.gz' : file } ,
swrOptions ,
} ) ;
}
public getExportBackupUrl ( ) : string {
return this . getValidUrlFor ( 'backup/export/file' ) ;
}
2023-09-01 20:40:24 +02:00
public startDownloads ( ) : AbortableApolloMutationResponse < StartDownloaderMutation > {
return this . doRequestNew < StartDownloaderMutation , StartDownloaderMutationVariables > (
GQLMethod . MUTATION ,
START_DOWNLOADER ,
{ } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public stopDownloads ( ) : AbortableApolloMutationResponse < StopDownloaderMutation > {
return this . doRequestNew < StopDownloaderMutation , StopDownloaderMutationVariables > (
GQLMethod . MUTATION ,
STOP_DOWNLOADER ,
{ } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public clearDownloads ( ) : AbortableApolloMutationResponse < ClearDownloaderMutation > {
return this . doRequestNew < ClearDownloaderMutation , ClearDownloaderMutationVariables > (
GQLMethod . MUTATION ,
CLEAR_DOWNLOADER ,
{ } ,
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public addChapterToDownloadQueue ( id : number ) : AbortableApolloMutationResponse < EnqueueChapterDownloadMutation > {
return this . doRequestNew < EnqueueChapterDownloadMutation , EnqueueChapterDownloadMutationVariables > (
GQLMethod . MUTATION ,
ENQUEUE_CHAPTER_DOWNLOAD ,
{ input : { id } } ,
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public removeChapterFromDownloadQueue ( id : number ) : AbortableApolloMutationResponse < DequeueChapterDownloadMutation > {
return this . doRequestNew < DequeueChapterDownloadMutation , DequeueChapterDownloadMutationVariables > (
GQLMethod . MUTATION ,
DEQUEUE_CHAPTER_DOWNLOAD ,
{ input : { id } } ,
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
public reorderChapterInDownloadQueue (
2023-09-01 20:40:24 +02:00
chapterId : number ,
2023-05-18 13:25:19 +02:00
position : number ,
2023-09-01 20:40:24 +02:00
) : AbortableApolloMutationResponse < ReorderChapterDownloadMutation > {
return this . doRequestNew < ReorderChapterDownloadMutation , ReorderChapterDownloadMutationVariables > (
GQLMethod . MUTATION ,
REORDER_CHAPTER_DOWNLOAD ,
{ input : { chapterId , to : position } } ,
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public addChaptersToDownloadQueue ( ids : number [ ] ) : AbortableApolloMutationResponse < EnqueueChapterDownloadsMutation > {
return this . doRequestNew < EnqueueChapterDownloadsMutation , EnqueueChapterDownloadsMutationVariables > (
GQLMethod . MUTATION ,
ENQUEUE_CHAPTER_DOWNLOADS ,
{ input : { ids } } ,
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:24 +02:00
public removeChaptersFromDownloadQueue (
ids : number [ ] ,
) : AbortableApolloMutationResponse < DequeueChapterDownloadsMutation > {
return this . doRequestNew < DequeueChapterDownloadsMutation , DequeueChapterDownloadsMutationVariables > (
GQLMethod . MUTATION ,
DEQUEUE_CHAPTER_DOWNLOADS ,
{ input : { ids } } ,
{ refetchQueries : [ GET_DOWNLOAD_STATUS ] } ,
) ;
2023-05-18 13:25:19 +02:00
}
public useGetRecentlyUpdatedChapters (
initialPages? : number ,
swrOptions? : SWRInfiniteOptions < PaginatedList < IMangaChapter > > ,
2023-05-23 13:27:38 +02:00
) : AbortableSWRInfiniteResponse < PaginatedList < IMangaChapter > > {
2023-05-18 13:25:19 +02:00
return this . doRequest ( HttpMethod . SWR_GET_INFINITE , '' , {
swrOptions : {
getEndpoint : ( page , previousData ) = >
previousData ? . hasNextPage ? ? true ? ` update/recentChapters/ ${ page } ` : null ,
initialSize : initialPages ,
. . . swrOptions ,
} as typeof swrOptions ,
} ) ;
}
2023-09-01 20:40:39 +02:00
public startGlobalUpdate ( ) : AbortableApolloMutationResponse < UpdateLibraryMangasMutation > ;
public startGlobalUpdate ( categories : number [ ] ) : AbortableApolloMutationResponse < UpdateCategoryMangasMutation > ;
public startGlobalUpdate (
categories? : number [ ] ,
) : AbortableApolloMutationResponse < UpdateCategoryMangasMutation | UpdateLibraryMangasMutation > {
if ( categories ? . length ) {
return this . doRequestNew < UpdateCategoryMangasMutation , UpdateCategoryMangasMutationVariables > (
GQLMethod . MUTATION ,
UPDATE_CATEGORY_MANGAS ,
{ input : { categories } } ,
) ;
}
return this . doRequestNew < UpdateLibraryMangasMutation , UpdateLibraryMangasMutationVariables > (
GQLMethod . MUTATION ,
UPDATE_LIBRARY_MANGAS ,
{ } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:39 +02:00
public resetGlobalUpdate ( ) : AbortableApolloMutationResponse < StopUpdaterMutation > {
return this . doRequestNew < StopUpdaterMutation , StopUpdaterMutationVariables > (
GQLMethod . MUTATION ,
STOP_UPDATER ,
{ } ,
) ;
2023-05-18 13:25:19 +02:00
}
2023-09-01 20:40:39 +02:00
public useGetGlobalUpdateSummary (
options? : QueryHookOptions < GetUpdateStatusQuery , GetUpdateStatusQueryVariables > ,
) : AbortableApolloUseQueryResponse < GetUpdateStatusQuery , GetUpdateStatusQueryVariables > {
return this . doRequestNew ( GQLMethod . USE_QUERY , GET_UPDATE_STATUS , { } , options ) ;
2023-05-18 13:25:19 +02:00
}
}
const requestManager = new RequestManager ( ) ;
export default requestManager ;