🔀 Merge pull request #373 from JannesV/feature/usenet

Feature/usenet
This commit is contained in:
Thomas Camlong
2022-09-02 11:19:51 +02:00
committed by GitHub
31 changed files with 1314 additions and 172 deletions

154
src/tools/hooks/api.ts Normal file
View File

@@ -0,0 +1,154 @@
import { useMutation, useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { Results } from 'sabnzbd-api';
import {
UsenetQueueRequestParams,
UsenetQueueResponse,
} from '../../pages/api/modules/usenet/queue';
import {
UsenetHistoryRequestParams,
UsenetHistoryResponse,
} from '../../pages/api/modules/usenet/history';
import { UsenetInfoRequestParams, UsenetInfoResponse } from '../../pages/api/modules/usenet';
import { UsenetPauseRequestParams } from '../../pages/api/modules/usenet/pause';
import { queryClient } from '../queryClient';
import { UsenetResumeRequestParams } from '../../pages/api/modules/usenet/resume';
const POLLING_INTERVAL = 2000;
export const useGetUsenetInfo = (params: UsenetInfoRequestParams) =>
useQuery(
['usenetInfo', params.serviceId],
async () =>
(
await axios.get<UsenetInfoResponse>('/api/modules/usenet', {
params,
})
).data,
{
refetchInterval: POLLING_INTERVAL,
keepPreviousData: true,
retry: 2,
enabled: !!params.serviceId,
}
);
export const useGetUsenetDownloads = (params: UsenetQueueRequestParams) =>
useQuery(
['usenetDownloads', ...Object.values(params)],
async () =>
(
await axios.get<UsenetQueueResponse>('/api/modules/usenet/queue', {
params,
})
).data,
{
refetchInterval: POLLING_INTERVAL,
keepPreviousData: true,
retry: 2,
}
);
export const useGetUsenetHistory = (params: UsenetHistoryRequestParams) =>
useQuery(
['usenetHistory', ...Object.values(params)],
async () =>
(
await axios.get<UsenetHistoryResponse>('/api/modules/usenet/history', {
params,
})
).data,
{
refetchInterval: POLLING_INTERVAL,
keepPreviousData: true,
retry: 2,
}
);
export const usePauseUsenetQueue = (params: UsenetPauseRequestParams) =>
useMutation(
['usenetPause', ...Object.values(params)],
async () =>
(
await axios.post<Results>(
'/api/modules/usenet/pause',
{},
{
params,
}
)
).data,
{
async onMutate() {
await queryClient.cancelQueries(['usenetInfo', params.serviceId]);
const previousInfo = queryClient.getQueryData<UsenetInfoResponse>([
'usenetInfo',
params.serviceId,
]);
if (previousInfo) {
queryClient.setQueryData<UsenetInfoResponse>(['usenetInfo', params.serviceId], {
...previousInfo,
paused: true,
});
}
return { previousInfo };
},
onError(err, _, context) {
if (context?.previousInfo) {
queryClient.setQueryData<UsenetInfoResponse>(
['usenetInfo', params.serviceId],
context.previousInfo
);
}
},
onSettled() {
queryClient.invalidateQueries(['usenetInfo', params.serviceId]);
},
}
);
export const useResumeUsenetQueue = (params: UsenetResumeRequestParams) =>
useMutation(
['usenetResume', ...Object.values(params)],
async () =>
(
await axios.post<Results>(
'/api/modules/usenet/resume',
{},
{
params,
}
)
).data,
{
async onMutate() {
await queryClient.cancelQueries(['usenetInfo', params.serviceId]);
const previousInfo = queryClient.getQueryData<UsenetInfoResponse>([
'usenetInfo',
params.serviceId,
]);
if (previousInfo) {
queryClient.setQueryData<UsenetInfoResponse>(['usenetInfo', params.serviceId], {
...previousInfo,
paused: false,
});
}
return { previousInfo };
},
onError(err, _, context) {
if (context?.previousInfo) {
queryClient.setQueryData<UsenetInfoResponse>(
['usenetInfo', params.serviceId],
context.previousInfo
);
}
},
onSettled() {
queryClient.invalidateQueries(['usenetInfo', params.serviceId]);
},
}
);

View File

@@ -0,0 +1,14 @@
import { useConfig } from '../state';
import { Config, ServiceType } from '../types';
export const useGetServiceByType = (...serviceTypes: ServiceType[]) => {
const { config } = useConfig();
return getServiceByType(config, ...serviceTypes);
};
export const getServiceByType = (config: Config, ...serviceTypes: ServiceType[]) =>
config.services.filter((s) => serviceTypes.includes(s.type));
export const getServiceById = (config: Config, id: string) =>
config.services.find((s) => s.id === id);

View File

@@ -0,0 +1,20 @@
import dayjs from 'dayjs';
import duration from 'dayjs/plugin/duration';
import { TFunction } from 'next-i18next';
dayjs.extend(duration);
export const parseDuration = (time: number, t: TFunction): string => {
const etaDuration = dayjs.duration(time, 's');
let eta = etaDuration.format(`s [${t('common:time.seconds')}]`);
if (etaDuration.asMinutes() > 1) {
eta = etaDuration.format(`m [${t('common:time.minutes')}] `) + eta;
}
if (etaDuration.asHours() > 1) {
eta = etaDuration.format(`H [${t('common:time.hours')}] `) + eta;
}
return eta;
};

3
src/tools/queryClient.ts Normal file
View File

@@ -0,0 +1,3 @@
import { QueryClient } from '@tanstack/react-query';
export const queryClient = new QueryClient();

View File

@@ -74,6 +74,7 @@ export const ServiceTypeList = [
'Transmission',
'Overseerr',
'Jellyseerr',
'Sabnzbd',
];
export type ServiceType =
| 'Other'
@@ -88,7 +89,8 @@ export type ServiceType =
| 'Sonarr'
| 'Overseerr'
| 'Jellyseerr'
| 'Transmission';
| 'Transmission'
| 'Sabnzbd';
export function tryMatchPort(name: string | undefined, form?: any) {
if (!name) {
@@ -114,6 +116,7 @@ export const portmap = [
{ name: 'emby', value: '8096' },
{ name: 'overseerr', value: '5055' },
{ name: 'dash.', value: '3001' },
{ name: 'sabnzbd', value: '8080' },
];
export const MatchingImages: {