[FEAT] upgrade upload of data...
This commit is contained in:
parent
6df71e3341
commit
88f65f0806
@ -1,6 +1,6 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef } from 'react';
|
||||||
|
|
||||||
import { Button, Text, useDisclosure } from '@chakra-ui/react';
|
import { Button, Tabs, Text, useDisclosure } from '@chakra-ui/react';
|
||||||
import { MdAdminPanelSettings, MdDeleteForever, MdEdit } from 'react-icons/md';
|
import { MdAdminPanelSettings, MdDeleteForever, MdEdit } from 'react-icons/md';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
@ -9,15 +9,14 @@ import { FormGroupShow } from '@/components/form/FormGroup';
|
|||||||
import { FormInput } from '@/components/form/FormInput';
|
import { FormInput } from '@/components/form/FormInput';
|
||||||
import { FormNumber } from '@/components/form/FormNumber';
|
import { FormNumber } from '@/components/form/FormNumber';
|
||||||
import { FormSelect } from '@/components/form/FormSelect';
|
import { FormSelect } from '@/components/form/FormSelect';
|
||||||
import { FormSelectMultiple } from '@/components/form/FormSelectMultiple';
|
|
||||||
import { FormTextarea } from '@/components/form/FormTextarea';
|
import { FormTextarea } from '@/components/form/FormTextarea';
|
||||||
import { ConfirmPopUp } from '@/components/popup/ConfirmPopUp';
|
import { ConfirmPopUp } from '@/components/popup/ConfirmPopUp';
|
||||||
import {
|
import {
|
||||||
DialogBody,
|
DialogBody,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogRoot,
|
DialogRoot,
|
||||||
} from '@/components/ui/dialog';
|
} from '@/components/ui/dialog';
|
||||||
import { useMediaService, useSpecificMedia } from '@/service/Media';
|
import { useMediaService, useSpecificMedia } from '@/service/Media';
|
||||||
import { useOrderedSeasons } from '@/service/Season';
|
import { useOrderedSeasons } from '@/service/Season';
|
||||||
@ -31,32 +30,31 @@ import { Formidable, useFormidable } from '../formidable';
|
|||||||
export type MediaEditPopUpProps = {};
|
export type MediaEditPopUpProps = {};
|
||||||
|
|
||||||
export const MediaEditPopUp = ({}: MediaEditPopUpProps) => {
|
export const MediaEditPopUp = ({}: MediaEditPopUpProps) => {
|
||||||
const { MediaId } = useParams();
|
const { mediaId } = useParams();
|
||||||
const MediaIdInt = isNullOrUndefined(MediaId)
|
const mediaIdInt = isNullOrUndefined(mediaId)
|
||||||
? undefined
|
? undefined
|
||||||
: parseInt(MediaId, 10);
|
: parseInt(mediaId, 10);
|
||||||
const { session } = useServiceContext();
|
const { session } = useServiceContext();
|
||||||
const { dataTypes } = useOrderedTypes(undefined);
|
const { dataTypes } = useOrderedTypes();
|
||||||
const { dataSeries } = useOrderedSeries(undefined);
|
const { dataSeries } = useOrderedSeries();
|
||||||
const { dataSeasons } = useOrderedSeasons(undefined);
|
const { dataSeasons } = useOrderedSeasons();
|
||||||
const { store } = useMediaService();
|
const { store } = useMediaService();
|
||||||
const { dataMedia } = useSpecificMedia(MediaIdInt);
|
const { dataMedia } = useSpecificMedia(mediaIdInt);
|
||||||
const [admin, setAdmin] = useState(false);
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const disclosure = useDisclosure();
|
const disclosure = useDisclosure();
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
navigate('../../', { relative: 'path' });
|
navigate('../../..', { relative: 'path' });
|
||||||
};
|
};
|
||||||
const onRemove = () => {
|
const onRemove = () => {
|
||||||
if (isNullOrUndefined(MediaIdInt)) {
|
if (isNullOrUndefined(mediaIdInt)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
store.remove(
|
store.remove(
|
||||||
MediaIdInt,
|
mediaIdInt,
|
||||||
MediaResource.remove({
|
MediaResource.remove({
|
||||||
restConfig: session.getRestConfig(),
|
restConfig: session.getRestConfig(),
|
||||||
params: {
|
params: {
|
||||||
id: MediaIdInt,
|
id: mediaIdInt,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -69,7 +67,7 @@ export const MediaEditPopUp = ({}: MediaEditPopUpProps) => {
|
|||||||
deltaConfig: { omit: ['covers'] },
|
deltaConfig: { omit: ['covers'] },
|
||||||
});
|
});
|
||||||
const onSave = async (dataDelta: MediaWrite) => {
|
const onSave = async (dataDelta: MediaWrite) => {
|
||||||
if (isNullOrUndefined(MediaIdInt)) {
|
if (isNullOrUndefined(mediaIdInt)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(`onSave = ${JSON.stringify(dataDelta, null, 2)}`);
|
console.log(`onSave = ${JSON.stringify(dataDelta, null, 2)}`);
|
||||||
@ -78,7 +76,7 @@ export const MediaEditPopUp = ({}: MediaEditPopUpProps) => {
|
|||||||
restConfig: session.getRestConfig(),
|
restConfig: session.getRestConfig(),
|
||||||
data: dataDelta,
|
data: dataDelta,
|
||||||
params: {
|
params: {
|
||||||
id: MediaIdInt,
|
id: mediaIdInt,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -99,8 +97,48 @@ export const MediaEditPopUp = ({}: MediaEditPopUpProps) => {
|
|||||||
{/* <DialogCloseButton ref={finalRef} /> */}
|
{/* <DialogCloseButton ref={finalRef} /> */}
|
||||||
|
|
||||||
<DialogBody pb={6} gap="0px" paddingLeft="18px">
|
<DialogBody pb={6} gap="0px" paddingLeft="18px">
|
||||||
{admin && (
|
<Tabs.Root defaultValue="edit" variant="outline">
|
||||||
<>
|
<Tabs.List>
|
||||||
|
<Tabs.Trigger value="edit">
|
||||||
|
<MdEdit />
|
||||||
|
Edit
|
||||||
|
</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger value="admin">
|
||||||
|
<MdAdminPanelSettings />
|
||||||
|
Admin
|
||||||
|
</Tabs.Trigger>
|
||||||
|
</Tabs.List>
|
||||||
|
{/* ---------------------- Other Tabs --------------------------- */}
|
||||||
|
<Tabs.Content value="edit">
|
||||||
|
<FormInput
|
||||||
|
name="name"
|
||||||
|
isRequired
|
||||||
|
label="Title"
|
||||||
|
ref={initialRef}
|
||||||
|
/>
|
||||||
|
<FormTextarea name="description" label="Description" />
|
||||||
|
<FormSelect name="typeId" options={dataTypes} label="Type" />
|
||||||
|
<FormSelect
|
||||||
|
name="seriesId"
|
||||||
|
options={dataSeries}
|
||||||
|
label="Series(s)"
|
||||||
|
/>
|
||||||
|
<FormSelect
|
||||||
|
name="seasonId"
|
||||||
|
options={dataSeasons}
|
||||||
|
label="Season"
|
||||||
|
/>
|
||||||
|
<FormNumber
|
||||||
|
name="episode"
|
||||||
|
label="Episode n°"
|
||||||
|
step={1}
|
||||||
|
//defaultValue={0}
|
||||||
|
min={0}
|
||||||
|
max={1000}
|
||||||
|
/>
|
||||||
|
</Tabs.Content>
|
||||||
|
{/* ---------------------- Other Tabs --------------------------- */}
|
||||||
|
<Tabs.Content value="admin">
|
||||||
<FormGroupShow isRequired label="Id">
|
<FormGroupShow isRequired label="Id">
|
||||||
<Text>{dataMedia?.id}</Text>
|
<Text>{dataMedia?.id}</Text>
|
||||||
</FormGroupShow>
|
</FormGroupShow>
|
||||||
@ -123,62 +161,18 @@ export const MediaEditPopUp = ({}: MediaEditPopUpProps) => {
|
|||||||
confirmTitle="Remove"
|
confirmTitle="Remove"
|
||||||
onConfirm={onRemove}
|
onConfirm={onRemove}
|
||||||
/>
|
/>
|
||||||
</>
|
</Tabs.Content>
|
||||||
)}
|
</Tabs.Root>
|
||||||
{!admin && (
|
|
||||||
<>
|
|
||||||
<FormInput
|
|
||||||
name="name"
|
|
||||||
isRequired
|
|
||||||
label="Title"
|
|
||||||
ref={initialRef}
|
|
||||||
/>
|
|
||||||
<FormTextarea name="description" label="Description" />
|
|
||||||
<FormSelect
|
|
||||||
name="TypeId"
|
|
||||||
options={dataTypes}
|
|
||||||
label="Type"
|
|
||||||
/>
|
|
||||||
<FormSelectMultiple
|
|
||||||
name="Series"
|
|
||||||
options={dataSeries}
|
|
||||||
label="Series(s)"
|
|
||||||
/>
|
|
||||||
<FormSelect name="SeasonId" options={dataSeasons} label="Season" />
|
|
||||||
<FormNumber
|
|
||||||
name="Media"
|
|
||||||
label="Media n°"
|
|
||||||
step={1}
|
|
||||||
//defaultValue={0}
|
|
||||||
min={0}
|
|
||||||
max={1000}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</DialogBody>
|
</DialogBody>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button
|
<Button onClick={onClose} marginRight="auto">
|
||||||
onClick={() => setAdmin((value) => !value)}
|
Cancel
|
||||||
marginRight="auto"
|
|
||||||
>
|
|
||||||
{admin ? (
|
|
||||||
<>
|
|
||||||
<MdEdit />
|
|
||||||
Edit
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<MdAdminPanelSettings />
|
|
||||||
Admin
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
{!admin && form.isFormModified && (
|
{form.isFormModified && (
|
||||||
<Button colorScheme="blue" mr={3} type="submit">
|
<Button colorPalette="blue" type="submit">
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button onClick={onClose}>Cancel</Button>
|
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</Formidable.From>
|
</Formidable.From>
|
||||||
</DialogContent>
|
</DialogContent>
|
@ -57,7 +57,8 @@ export const SelectMultiple = ({
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return transformedOption.filter((element) => {
|
return transformedOption.filter((element) => {
|
||||||
return values.includes(element[keyKey]);
|
console.log(`plop ${JSON.stringify(values, null, 2)}`);
|
||||||
|
return values?.includes(element[keyKey]);
|
||||||
});
|
});
|
||||||
}, [values, transformedOption]);
|
}, [values, transformedOption]);
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { Box, Button, Flex, Input, Table, Text } from '@chakra-ui/react';
|
import { Box, Button, Flex, Input, Table, Text } from '@chakra-ui/react';
|
||||||
import { LuTrash } from 'react-icons/lu';
|
import { LuTrash } from 'react-icons/lu';
|
||||||
@ -12,9 +12,10 @@ import {
|
|||||||
Series,
|
Series,
|
||||||
SeriesResource,
|
SeriesResource,
|
||||||
Type,
|
Type,
|
||||||
TypeResource
|
TypeResource,
|
||||||
} from '@/back-api';
|
} from '@/back-api';
|
||||||
import { PageLayout } from '@/components/Layout/PageLayout';
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
|
import { ParameterLayout } from '@/components/ParameterLayout';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { FormSelect } from '@/components/form/FormSelect';
|
import { FormSelect } from '@/components/form/FormSelect';
|
||||||
import { Formidable, useFormidable } from '@/components/formidable';
|
import { Formidable, useFormidable } from '@/components/formidable';
|
||||||
@ -23,10 +24,20 @@ import {
|
|||||||
NumberInputField,
|
NumberInputField,
|
||||||
NumberInputRoot,
|
NumberInputRoot,
|
||||||
} from '@/components/ui/number-input';
|
} from '@/components/ui/number-input';
|
||||||
import { useMediaService } from '@/service/Media';
|
import {
|
||||||
import { useOrderedSeries, useOrderedSeriesWithType, useSeriesService } from '@/service/Series';
|
MediaExpandSeason,
|
||||||
|
useFilteredMedia,
|
||||||
|
useMediaExpandSeason,
|
||||||
|
useMediaService,
|
||||||
|
} from '@/service/Media';
|
||||||
|
import {
|
||||||
|
useOrderedSeries,
|
||||||
|
useOrderedSeriesWithType,
|
||||||
|
useSeriesService,
|
||||||
|
} from '@/service/Series';
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { useOrderedTypes, useTypeService } from '@/service/Type';
|
import { useOrderedTypes, useTypeService } from '@/service/Type';
|
||||||
|
import { useDebounce, useDebouncedCallback } from '@/utils/debouncedCallback';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
|
||||||
export class ElementList {
|
export class ElementList {
|
||||||
@ -40,7 +51,7 @@ export class ElementList {
|
|||||||
export class FileParsedElement {
|
export class FileParsedElement {
|
||||||
public isSended: boolean = false;
|
public isSended: boolean = false;
|
||||||
public nameDetected: boolean = false;
|
public nameDetected: boolean = false;
|
||||||
public mediaIdDetected: boolean = false;
|
public episodeDetected: boolean = false;
|
||||||
public seasonId?: Season['id'] = undefined;
|
public seasonId?: Season['id'] = undefined;
|
||||||
public seriesId?: Series['id'] = undefined;
|
public seriesId?: Series['id'] = undefined;
|
||||||
constructor(
|
constructor(
|
||||||
@ -50,7 +61,7 @@ export class FileParsedElement {
|
|||||||
public universe?: string,
|
public universe?: string,
|
||||||
public series?: string,
|
public series?: string,
|
||||||
public season?: number,
|
public season?: number,
|
||||||
public mediaId?: number
|
public episode?: number
|
||||||
) {
|
) {
|
||||||
console.log(`Unique element: ${uniqueId}`);
|
console.log(`Unique element: ${uniqueId}`);
|
||||||
// nothing to do.
|
// nothing to do.
|
||||||
@ -66,7 +77,11 @@ export class FileFailParsedElement {
|
|||||||
// nothing to do.
|
// nothing to do.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
type InspectionType = {
|
||||||
|
episodeDetected: boolean;
|
||||||
|
nameDetected: boolean;
|
||||||
|
media: MediaExpandSeason;
|
||||||
|
};
|
||||||
type FormInsertData = {
|
type FormInsertData = {
|
||||||
typeId?: number;
|
typeId?: number;
|
||||||
seriesId?: number;
|
seriesId?: number;
|
||||||
@ -81,26 +96,95 @@ export const AddPage = () => {
|
|||||||
|
|
||||||
const [needSend, setNeedSend] = useState<boolean>(false);
|
const [needSend, setNeedSend] = useState<boolean>(false);
|
||||||
|
|
||||||
// list of all files already registered in the bdd to compare with the current list of files.
|
|
||||||
const [listFileInBdd, setListFileInBdd] = useState<any[] | undefined>(
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
|
|
||||||
const { dataTypes } = useOrderedTypes();
|
const { dataTypes } = useOrderedTypes();
|
||||||
const { dataSeries: dataSeriesFull } = useOrderedSeries();
|
const { dataSeries: dataSeriesFull } = useOrderedSeries();
|
||||||
const { store: storeType } = useTypeService();
|
const { store: storeType } = useTypeService();
|
||||||
const { store: storeSeries } = useSeriesService();
|
const { store: storeSeries } = useSeriesService();
|
||||||
const { store: storeMedia } = useMediaService();
|
const { store: storeMedia } = useMediaService();
|
||||||
const { session } = useServiceContext();
|
const { session } = useServiceContext();
|
||||||
|
|
||||||
const form = useFormidable<FormInsertData>({
|
const form = useFormidable<FormInsertData>({
|
||||||
configuration: {
|
configuration: {
|
||||||
enableModifyNotification: false,
|
enableModifyNotification: false,
|
||||||
enableReset: false,
|
enableReset: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
// list of all files already registered in the bdd to compare with the current list of files.
|
||||||
|
const [listFileInBdd, setListFileInBdd] = useState<
|
||||||
|
InspectionType[] | undefined
|
||||||
|
>(undefined);
|
||||||
|
const formValuesSelectForCheck = useDebounce(form.values, 700);
|
||||||
|
const { medias } = useFilteredMedia(
|
||||||
|
formValuesSelectForCheck.typeId,
|
||||||
|
formValuesSelectForCheck.seriesId
|
||||||
|
);
|
||||||
|
const { mediasExpand } = useMediaExpandSeason(medias);
|
||||||
|
useEffect(() => {
|
||||||
|
handleCheck('');
|
||||||
|
}, [
|
||||||
|
formValuesSelectForCheck,
|
||||||
|
formValuesSelectForCheck.typeId,
|
||||||
|
mediasExpand,
|
||||||
|
parsedElement,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleCheck = useDebouncedCallback((_newValue) => {
|
||||||
|
console.log(`values has changes ... ${mediasExpand.length} medias`);
|
||||||
|
// find the good case: (ignore the universe that have no sense...)
|
||||||
|
if (formValuesSelectForCheck.typeId === undefined) {
|
||||||
|
setListFileInBdd(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const out: InspectionType[] = [];
|
||||||
|
mediasExpand.forEach((media) => {
|
||||||
|
out.push({
|
||||||
|
episodeDetected: false,
|
||||||
|
nameDetected: false,
|
||||||
|
media,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// clear previous data:
|
||||||
|
out.forEach((elem) => {
|
||||||
|
elem.episodeDetected = false;
|
||||||
|
elem.nameDetected = false;
|
||||||
|
});
|
||||||
|
parsedElement.forEach((elem) => {
|
||||||
|
elem.episodeDetected = false;
|
||||||
|
elem.nameDetected = false;
|
||||||
|
});
|
||||||
|
// Detect the identical season + identical ID:
|
||||||
|
console.log(`check:'${JSON.stringify(parsedElement, null, 2)}'`);
|
||||||
|
out.forEach((checkElem) => {
|
||||||
|
parsedElement.forEach((parsedElem) => {
|
||||||
|
if (
|
||||||
|
`${parsedElem.season}` === `${checkElem.media?.season?.name}` &&
|
||||||
|
`${parsedElem.episode}` === `${checkElem.media?.episode}`
|
||||||
|
) {
|
||||||
|
checkElem.episodeDetected = true;
|
||||||
|
parsedElem.episodeDetected = true;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
parsedElem.title?.length !== undefined &&
|
||||||
|
parsedElem.title?.length !== 0 &&
|
||||||
|
checkElem.media?.name?.length !== 0 &&
|
||||||
|
checkElem.media?.name?.length !== 0 &&
|
||||||
|
(parsedElem.title.startsWith(checkElem.media?.name) ||
|
||||||
|
checkElem.media?.name.startsWith(parsedElem.title))
|
||||||
|
) {
|
||||||
|
checkElem.nameDetected = true;
|
||||||
|
parsedElem.nameDetected = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setListFileInBdd(
|
||||||
|
out.sort((a, b) => {
|
||||||
|
const aPriority = a.episodeDetected || a.nameDetected ? 1 : 0;
|
||||||
|
const bPriority = b.episodeDetected || b.nameDetected ? 1 : 0;
|
||||||
|
return bPriority - aPriority;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}, 1000);
|
||||||
// I think this does not work ...
|
// I think this does not work ...
|
||||||
const { dataSeries } = useOrderedSeriesWithType(form.values["typeId"]);
|
const { dataSeries } = useOrderedSeriesWithType(form.values.typeId);
|
||||||
|
|
||||||
const updateNeedSend = () => {
|
const updateNeedSend = () => {
|
||||||
if (parsedElement.length === 0) {
|
if (parsedElement.length === 0) {
|
||||||
@ -145,8 +229,8 @@ export const AddPage = () => {
|
|||||||
updateNeedSend();
|
updateNeedSend();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMediaId = (data: FileParsedElement, value: any): void => {
|
const onEpisode = (data: FileParsedElement, value: any): void => {
|
||||||
data.mediaId = value;
|
data.episode = value;
|
||||||
setParsedElement([...parsedElement]);
|
setParsedElement([...parsedElement]);
|
||||||
updateNeedSend();
|
updateNeedSend();
|
||||||
};
|
};
|
||||||
@ -164,14 +248,15 @@ export const AddPage = () => {
|
|||||||
//setSuggestedSeason(undefined);
|
//setSuggestedSeason(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
const regex = /^(?:(?<universe>[\w. -]+):)?((?<series>[\w. -]+?)((-s| S)(?<season>\d{1,5}))?(?:(-e|E)(?<episode>\d{1,5}))[- ])?\s*(?<title>.+?)\.(webm|WEBM|Webm|mkv|MKV|Mkv)$/;
|
const regex =
|
||||||
|
/^(?:(?<universe>[\w. -]+):)?((?<series>[\w. -]+?)((-s| S)(?<season>\d{1,5}))?(?:(-e|E)(?<episode>\d{1,5}))[- ])?\s*(?<title>.+?)\.(webm|WEBM|Webm|mkv|MKV|Mkv)$/;
|
||||||
|
|
||||||
const addFileWithMetaData = (file: File, id: number) => {
|
const addFileWithMetaData = (file: File, id: number) => {
|
||||||
// parsedElement: FileParsedElement[] = [];
|
// parsedElement: FileParsedElement[] = [];
|
||||||
let universe: string | undefined = undefined;
|
let universe: string | undefined = undefined;
|
||||||
let series: string | undefined = undefined;
|
let series: string | undefined = undefined;
|
||||||
let season: number | undefined = undefined;
|
let season: number | undefined = undefined;
|
||||||
let mediaIdNumber: number | undefined = undefined;
|
let episodeNumber: number | undefined = undefined;
|
||||||
let title: string = '';
|
let title: string = '';
|
||||||
|
|
||||||
form.restoreValues();
|
form.restoreValues();
|
||||||
@ -180,21 +265,25 @@ export const AddPage = () => {
|
|||||||
|
|
||||||
const match = file.name.match(regex);
|
const match = file.name.match(regex);
|
||||||
if (match?.groups) {
|
if (match?.groups) {
|
||||||
universe = match.groups.universe || undefined;
|
universe = match.groups.universe || undefined;
|
||||||
series = match.groups.series ? match.groups.series.trim() : undefined;
|
series = match.groups.series ? match.groups.series.trim() : undefined;
|
||||||
season = match.groups.season? parseInt(match.groups.season, 10) : undefined;
|
season = match.groups.season
|
||||||
mediaIdNumber = match.groups.episode ? parseInt(match.groups.episode, 10) : undefined;
|
? parseInt(match.groups.season, 10)
|
||||||
title = match.groups.title.trim();
|
: undefined;
|
||||||
|
episodeNumber = match.groups.episode
|
||||||
|
? parseInt(match.groups.episode, 10)
|
||||||
|
: undefined;
|
||||||
|
title = match.groups.title.trim();
|
||||||
} else {
|
} else {
|
||||||
console.log("❌ not match :", file.name);
|
console.log('❌ not match :', file.name);
|
||||||
title = file.name.trim();
|
title = file.name.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (season && isNaN(season)) {
|
if (season && isNaN(season)) {
|
||||||
season = undefined;
|
season = undefined;
|
||||||
}
|
}
|
||||||
if (mediaIdNumber && isNaN(mediaIdNumber)) {
|
if (episodeNumber && isNaN(episodeNumber)) {
|
||||||
mediaIdNumber = undefined;
|
episodeNumber = undefined;
|
||||||
}
|
}
|
||||||
// remove extension
|
// remove extension
|
||||||
title = title.replace(new RegExp('\\.(webm|WEBM|Webm|mkv|MKV|Mkv)'), '');
|
title = title.replace(new RegExp('\\.(webm|WEBM|Webm|mkv|MKV|Mkv)'), '');
|
||||||
@ -205,7 +294,7 @@ export const AddPage = () => {
|
|||||||
universe,
|
universe,
|
||||||
series,
|
series,
|
||||||
season,
|
season,
|
||||||
mediaIdNumber
|
episodeNumber
|
||||||
);
|
);
|
||||||
console.log(`==>${JSON.stringify(tmp, null, 2)}`);
|
console.log(`==>${JSON.stringify(tmp, null, 2)}`);
|
||||||
|
|
||||||
@ -316,10 +405,10 @@ export const AddPage = () => {
|
|||||||
typeId: `${form.values['typeId']}`,
|
typeId: `${form.values['typeId']}`,
|
||||||
seriesId: `${form.values['seriesId']}`,
|
seriesId: `${form.values['seriesId']}`,
|
||||||
season: `${parsedElement[index].season}`,
|
season: `${parsedElement[index].season}`,
|
||||||
episode: `${parsedElement[index].mediaId}`,
|
episode: `${parsedElement[index].episode}`,
|
||||||
};
|
};
|
||||||
console.log(`data= ${JSON.stringify(data, null, 2)}`);
|
console.log(`data= ${JSON.stringify(data, null, 2)}`);
|
||||||
console.error("Not_ implemented");
|
console.error('Not_ implemented');
|
||||||
storeMedia
|
storeMedia
|
||||||
.update(
|
.update(
|
||||||
MediaResource.uploadMedia({
|
MediaResource.uploadMedia({
|
||||||
@ -384,7 +473,7 @@ export const AddPage = () => {
|
|||||||
restConfig: session.getRestConfig(),
|
restConfig: session.getRestConfig(),
|
||||||
data: {
|
data: {
|
||||||
name: data,
|
name: data,
|
||||||
parentId: form.values["typeId"]
|
parentId: form.values['typeId'],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -394,140 +483,160 @@ export const AddPage = () => {
|
|||||||
<>
|
<>
|
||||||
<TopBar title="Add new media" />
|
<TopBar title="Add new media" />
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Flex
|
<ParameterLayout.Root>
|
||||||
direction="column"
|
<ParameterLayout.HeaderBase
|
||||||
width="80%"
|
title="New Media"
|
||||||
marginX="auto"
|
description="Add a new media in the library."
|
||||||
padding="10px"
|
/>
|
||||||
gap="10px"
|
<ParameterLayout.Content>
|
||||||
>
|
<Flex direction="column" width="full">
|
||||||
<Flex direction="column" width="full">
|
<Flex>
|
||||||
<Flex>
|
<Text flex={1}>format:</Text>
|
||||||
<Text flex={1}>format:</Text>
|
<Text flex={4}>
|
||||||
<Text flex={4}>
|
The format of the media permit to automatic find meta-data:
|
||||||
The format of the media permit to automatic find meta-data:<br />
|
<br />
|
||||||
<li>Universe:Series name-s05-e22-Title.webm/mkv</li>
|
<li>Universe:Series name-s05-e22-Title.webm/mkv</li>
|
||||||
<li>Universe:Series name S05E22 Title.webm/mkv</li>
|
<li>Universe:Series name S05E22 Title.webm/mkv</li>
|
||||||
<b>example:</b> Stargate:SG1-s05-e22-Tolans.webm
|
<b>example:</b> Stargate:SG1-s05-e22-Tolans.webm
|
||||||
</Text>
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
<Flex>
|
||||||
|
<Text flex={1}>Media:</Text>
|
||||||
|
<Input
|
||||||
|
flex={4}
|
||||||
|
type="file"
|
||||||
|
placeholder="Select a media file"
|
||||||
|
accept=".webm,.mkv"
|
||||||
|
multiple
|
||||||
|
onChange={onChangeFile}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex>
|
</ParameterLayout.Content>
|
||||||
<Text flex={1}>Media:</Text>
|
<ParameterLayout.Footer />
|
||||||
<Input
|
</ParameterLayout.Root>
|
||||||
flex={4}
|
|
||||||
type="file"
|
|
||||||
placeholder="Select a media file"
|
|
||||||
accept=".webm,.mkv"
|
|
||||||
multiple
|
|
||||||
onChange={onChangeFile}
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
{parsedElement && parsedElement.length !== 0 && (
|
|
||||||
<Formidable.From form={form} onSubmit={sendFile}>
|
|
||||||
<Text fontSize="30px">Meta-data:</Text>
|
|
||||||
<FormSelect
|
|
||||||
label="Type"
|
|
||||||
name="typeId"
|
|
||||||
options={dataTypes}
|
|
||||||
addNewItem={addNewType}
|
|
||||||
isRequired
|
|
||||||
/>
|
|
||||||
<FormSelect
|
|
||||||
label="Series"
|
|
||||||
name="seriesId"
|
|
||||||
options={dataSeries}
|
|
||||||
addNewItem={addNewSeries}
|
|
||||||
suggestion={suggestedSeries}
|
|
||||||
disabled={form.values["typeId"] === undefined}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Table.Root
|
{parsedElement && parsedElement.length !== 0 && (
|
||||||
colorPalette="striped"
|
<Formidable.From form={form} onSubmit={sendFile}>
|
||||||
colorScheme="teal"
|
<ParameterLayout.Root>
|
||||||
background="gray.700"
|
<ParameterLayout.HeaderBase
|
||||||
>
|
title="Meta-data:"
|
||||||
<Table.Header>
|
description="Edit the data that might be upload."
|
||||||
<Table.Row>
|
/>
|
||||||
<Table.ColumnHeader width="10%">
|
<ParameterLayout.Content>
|
||||||
Season ID
|
<FormSelect
|
||||||
</Table.ColumnHeader>
|
label="Type"
|
||||||
<Table.ColumnHeader width="10%">
|
name="typeId"
|
||||||
Media ID
|
options={dataTypes}
|
||||||
</Table.ColumnHeader>
|
addNewItem={addNewType}
|
||||||
<Table.ColumnHeader width="full">Title</Table.ColumnHeader>
|
isRequired
|
||||||
<Table.ColumnHeader>actions</Table.ColumnHeader>
|
/>
|
||||||
</Table.Row>
|
<FormSelect
|
||||||
</Table.Header>
|
label="Series"
|
||||||
<Table.Body>
|
name="seriesId"
|
||||||
{parsedElement.map((data) => (
|
options={dataSeries}
|
||||||
<Table.Row key={data.uniqueId}>
|
addNewItem={addNewSeries}
|
||||||
<Table.Cell>
|
suggestion={suggestedSeries}
|
||||||
{form.values["seriesId"] &&
|
disabled={form.values['typeId'] === undefined}
|
||||||
<NumberInputRoot
|
/>
|
||||||
value={data.season ? `${data.season}` : undefined}
|
|
||||||
onValueChange={(e) => onSeasonId(data, e.value)}
|
<Table.Root
|
||||||
min={0}
|
colorPalette="striped"
|
||||||
max={5000}
|
colorScheme="teal"
|
||||||
backgroundColor={
|
background="gray.700"
|
||||||
data.mediaIdDetected === true
|
>
|
||||||
? 'darkred'
|
<Table.Header>
|
||||||
: undefined
|
<Table.Row>
|
||||||
}
|
<Table.ColumnHeader width="10%">
|
||||||
>
|
Season ID
|
||||||
<NumberInputField />
|
</Table.ColumnHeader>
|
||||||
</NumberInputRoot>
|
<Table.ColumnHeader width="10%">
|
||||||
}
|
Media ID
|
||||||
</Table.Cell>
|
</Table.ColumnHeader>
|
||||||
<Table.Cell>
|
<Table.ColumnHeader width="full">
|
||||||
{form.values["seriesId"] &&
|
Title
|
||||||
<NumberInputRoot
|
</Table.ColumnHeader>
|
||||||
value={data.mediaId ? `${data.mediaId}` : undefined}
|
<Table.ColumnHeader>actions</Table.ColumnHeader>
|
||||||
onValueChange={(e) => onMediaId(data, e.value)}
|
|
||||||
min={0}
|
|
||||||
max={5000}
|
|
||||||
backgroundColor={
|
|
||||||
data.mediaIdDetected === true
|
|
||||||
? 'darkred'
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<NumberInputField />
|
|
||||||
</NumberInputRoot>
|
|
||||||
}
|
|
||||||
</Table.Cell>
|
|
||||||
<Table.Cell>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
placeholder="Name of the Media"
|
|
||||||
value={data.title}
|
|
||||||
onChange={(e) => onTitle(data, e.target.value)}
|
|
||||||
backgroundColor={
|
|
||||||
data.title === '' ? 'darkred' : undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{data.nameDetected === true && (
|
|
||||||
<>
|
|
||||||
<br />
|
|
||||||
<Text as="span" color="@danger">
|
|
||||||
^^^This title already exist !!!
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Table.Cell>
|
|
||||||
<Table.Cell>
|
|
||||||
<Button
|
|
||||||
colorPalette="@danger"
|
|
||||||
onClick={(e) => removeElementFromList(data, e.target)}
|
|
||||||
>
|
|
||||||
<LuTrash /> Remove
|
|
||||||
</Button>
|
|
||||||
</Table.Cell>
|
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
))}
|
</Table.Header>
|
||||||
</Table.Body>
|
<Table.Body>
|
||||||
</Table.Root>
|
{parsedElement.map((data) => (
|
||||||
<Flex marginY="15px">
|
<Table.Row key={data.uniqueId}>
|
||||||
|
<Table.Cell>
|
||||||
|
{form.values['seriesId'] && (
|
||||||
|
<NumberInputRoot
|
||||||
|
value={data.season ? `${data.season}` : undefined}
|
||||||
|
onValueChange={(e) => onSeasonId(data, e.value)}
|
||||||
|
min={0}
|
||||||
|
max={5000}
|
||||||
|
backgroundColor={
|
||||||
|
data.episodeDetected === true
|
||||||
|
? 'darkred'
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<NumberInputField />
|
||||||
|
</NumberInputRoot>
|
||||||
|
)}
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
{form.values['seriesId'] && (
|
||||||
|
<NumberInputRoot
|
||||||
|
value={
|
||||||
|
data.episode ? `${data.episode}` : undefined
|
||||||
|
}
|
||||||
|
onValueChange={(e) => onEpisode(data, e.value)}
|
||||||
|
min={0}
|
||||||
|
max={5000}
|
||||||
|
backgroundColor={
|
||||||
|
data.episodeDetected === true
|
||||||
|
? 'darkred'
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<NumberInputField />
|
||||||
|
</NumberInputRoot>
|
||||||
|
)}
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
placeholder="Name of the Media"
|
||||||
|
value={data.title}
|
||||||
|
onChange={(e) => onTitle(data, e.target.value)}
|
||||||
|
backgroundColor={
|
||||||
|
data.title === ''
|
||||||
|
? 'purple'
|
||||||
|
: data.nameDetected === true
|
||||||
|
? 'darkred'
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{data.nameDetected === true && (
|
||||||
|
<>
|
||||||
|
<br />
|
||||||
|
<Text as="span" color="red">
|
||||||
|
^^^This title already exist !!!
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Button
|
||||||
|
colorPalette="@danger"
|
||||||
|
onClick={(e) =>
|
||||||
|
removeElementFromList(data, e.target)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<LuTrash /> Remove
|
||||||
|
</Button>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
))}
|
||||||
|
</Table.Body>
|
||||||
|
</Table.Root>
|
||||||
|
</ParameterLayout.Content>
|
||||||
|
<ParameterLayout.Footer>
|
||||||
<Button
|
<Button
|
||||||
colorPalette="brand"
|
colorPalette="brand"
|
||||||
type="submit"
|
type="submit"
|
||||||
@ -537,51 +646,51 @@ export const AddPage = () => {
|
|||||||
>
|
>
|
||||||
<MdCloudUpload /> Upload
|
<MdCloudUpload /> Upload
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</ParameterLayout.Footer>
|
||||||
</Formidable.From>
|
</ParameterLayout.Root>
|
||||||
)}
|
</Formidable.From>
|
||||||
|
)}
|
||||||
|
|
||||||
{listFileInBdd && (
|
{listFileInBdd && (
|
||||||
<Table.Root
|
<ParameterLayout.Root>
|
||||||
fontPalette="striped"
|
<ParameterLayout.HeaderBase
|
||||||
colorScheme="teal"
|
title="In base"
|
||||||
background="gray.700"
|
description="List of file in the base for the Type/series ... (2 seconds before update)"
|
||||||
>
|
/>
|
||||||
<Table.Header>
|
<ParameterLayout.Content>
|
||||||
<Table.Row>
|
<Table.Root
|
||||||
<Table.ColumnHeader>Media ID</Table.ColumnHeader>
|
fontPalette="striped"
|
||||||
<Table.ColumnHeader width="full">Title</Table.ColumnHeader>
|
colorScheme="teal"
|
||||||
<Table.ColumnHeader>actions</Table.ColumnHeader>
|
background="gray.700"
|
||||||
</Table.Row>
|
>
|
||||||
</Table.Header>
|
<Table.Header>
|
||||||
<Table.Body>
|
|
||||||
{listFileInBdd.map((data) => (
|
|
||||||
<Table.Row>
|
<Table.Row>
|
||||||
<Table.Cell>
|
<Table.ColumnHeader>Media ID</Table.ColumnHeader>
|
||||||
<Text
|
<Table.ColumnHeader>Data ID</Table.ColumnHeader>
|
||||||
color={
|
<Table.ColumnHeader>Season</Table.ColumnHeader>
|
||||||
data.episodeDetected === true ? 'red' : undefined
|
<Table.ColumnHeader>Episode</Table.ColumnHeader>
|
||||||
}
|
<Table.ColumnHeader width="full">Title</Table.ColumnHeader>
|
||||||
>
|
<Table.ColumnHeader>Date</Table.ColumnHeader>
|
||||||
{data.MediaId}
|
<Table.ColumnHeader>Actions</Table.ColumnHeader>
|
||||||
</Text>
|
|
||||||
</Table.Cell>
|
|
||||||
<Table.Cell>
|
|
||||||
<Text
|
|
||||||
color={data.nameDetected === true ? 'red' : undefined}
|
|
||||||
>
|
|
||||||
{data.title}
|
|
||||||
</Text>
|
|
||||||
</Table.Cell>
|
|
||||||
<Table.Cell></Table.Cell>
|
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
))}
|
</Table.Header>
|
||||||
</Table.Body>
|
<Table.Body>
|
||||||
</Table.Root>
|
{listFileInBdd.map((data) => (
|
||||||
)}
|
<MediaDetectionDetail data={data} />
|
||||||
|
))}
|
||||||
{parsedFailedElement && (
|
</Table.Body>
|
||||||
<>
|
</Table.Root>
|
||||||
|
</ParameterLayout.Content>
|
||||||
|
<ParameterLayout.Footer />
|
||||||
|
</ParameterLayout.Root>
|
||||||
|
)}
|
||||||
|
{parsedFailedElement && (
|
||||||
|
<ParameterLayout.Root>
|
||||||
|
<ParameterLayout.HeaderBase
|
||||||
|
title="Rejected:"
|
||||||
|
description="List of files that has been removed due to parsing error"
|
||||||
|
/>
|
||||||
|
<ParameterLayout.Content>
|
||||||
<Text fontSize="30px">Rejected:</Text>
|
<Text fontSize="30px">Rejected:</Text>
|
||||||
<Table.Root
|
<Table.Root
|
||||||
colorPalette="striped"
|
colorPalette="striped"
|
||||||
@ -603,10 +712,12 @@ export const AddPage = () => {
|
|||||||
))}
|
))}
|
||||||
</Table.Body>
|
</Table.Body>
|
||||||
</Table.Root>
|
</Table.Root>
|
||||||
</>
|
</ParameterLayout.Content>
|
||||||
)}
|
<ParameterLayout.Footer />
|
||||||
<Box height="250px" width="full" />
|
</ParameterLayout.Root>
|
||||||
</Flex>
|
)}
|
||||||
|
<Box height="50%" minHeight="50%" width="99%" />
|
||||||
|
{/* upload pop-in */}
|
||||||
{indexUpload !== undefined && (
|
{indexUpload !== undefined && (
|
||||||
<PopUpUploadProgress
|
<PopUpUploadProgress
|
||||||
title="Upload File(s)"
|
title="Upload File(s)"
|
||||||
@ -624,3 +735,37 @@ export const AddPage = () => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
export const MediaDetectionDetail = ({ data }: { data: InspectionType }) => {
|
||||||
|
return (
|
||||||
|
<Table.Row>
|
||||||
|
<Table.Cell>
|
||||||
|
<Text>{data.media.id}</Text>
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Text>{data.media.dataId.toUpperCase()}</Text>
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Text color={data.episodeDetected === true ? 'red' : undefined}>
|
||||||
|
{data.media.season?.name}
|
||||||
|
</Text>
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Text color={data.episodeDetected === true ? 'red' : undefined}>
|
||||||
|
{data.media.episode}
|
||||||
|
</Text>
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Text
|
||||||
|
userSelect="text"
|
||||||
|
color={data.nameDetected === true ? 'red' : undefined}
|
||||||
|
>
|
||||||
|
{data.media.name}
|
||||||
|
</Text>
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Text>{data.media.date}</Text>
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell></Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -11,10 +11,10 @@ import { Route, Routes, useNavigate } from 'react-router-dom';
|
|||||||
import { EmptyEnd } from '@/components/EmptyEnd';
|
import { EmptyEnd } from '@/components/EmptyEnd';
|
||||||
import { PageLayout } from '@/components/Layout/PageLayout';
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
|
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { DisplayMediaFullId } from '@/components/media/DisplayMediaFullId';
|
import { DisplayMediaFullId } from '@/components/media/DisplayMediaFullId';
|
||||||
import { SeasonEditPopUp } from '@/components/popup/AlbumEditPopUp';
|
import { SeasonEditPopUp } from '@/components/popup/AlbumEditPopUp';
|
||||||
import { MediaEditPopUp } from '@/components/popup/TrackEditPopUp';
|
import { MediaEditPopUp } from '@/components/popup/MediaEditPopUp';
|
||||||
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorModeValue } from '@/components/ui/color-mode';
|
||||||
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
||||||
|
@ -7,12 +7,16 @@ import { Covers } from '@/components/Cover';
|
|||||||
import { EmptyEnd } from '@/components/EmptyEnd';
|
import { EmptyEnd } from '@/components/EmptyEnd';
|
||||||
import { PageLayout } from '@/components/Layout/PageLayout';
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
import { SeasonEditPopUp } from '@/components/popup/AlbumEditPopUp';
|
|
||||||
import { MediaEditPopUp } from '@/components/popup/TrackEditPopUp';
|
|
||||||
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
||||||
|
import { SeasonEditPopUp } from '@/components/popup/AlbumEditPopUp';
|
||||||
|
import { MediaEditPopUp } from '@/components/popup/MediaEditPopUp';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorModeValue } from '@/components/ui/color-mode';
|
||||||
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
||||||
import { useActivePlaylistService, useSeasonVideo, useSpecificSeason } from '@/service';
|
import {
|
||||||
|
useActivePlaylistService,
|
||||||
|
useSeasonVideo,
|
||||||
|
useSpecificSeason,
|
||||||
|
} from '@/service';
|
||||||
|
|
||||||
export const SeasonDetailPage = () => {
|
export const SeasonDetailPage = () => {
|
||||||
const { SeasonId } = useParams();
|
const { SeasonId } = useParams();
|
||||||
|
@ -7,9 +7,9 @@ import { Covers } from '@/components/Cover';
|
|||||||
import { EmptyEnd } from '@/components/EmptyEnd';
|
import { EmptyEnd } from '@/components/EmptyEnd';
|
||||||
import { PageLayout } from '@/components/Layout/PageLayout';
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
import { SeasonEditPopUp } from '@/components/popup/AlbumEditPopUp';
|
|
||||||
import { MediaEditPopUp } from '@/components/popup/TrackEditPopUp';
|
|
||||||
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
||||||
|
import { SeasonEditPopUp } from '@/components/popup/AlbumEditPopUp';
|
||||||
|
import { MediaEditPopUp } from '@/components/popup/MediaEditPopUp';
|
||||||
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
||||||
import { useSeasonVideo, useSpecificSeason } from '@/service/Season';
|
import { useSeasonVideo, useSpecificSeason } from '@/service/Season';
|
||||||
import { useSpecificSeries } from '@/service/Series';
|
import { useSpecificSeries } from '@/service/Series';
|
||||||
|
@ -11,7 +11,7 @@ import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
|||||||
//import { useMediasOfAType } from '@/service/Media';
|
//import { useMediasOfAType } from '@/service/Media';
|
||||||
import { DisplayMediaFull } from '@/components/media/DisplayMediaFull';
|
import { DisplayMediaFull } from '@/components/media/DisplayMediaFull';
|
||||||
import { TypeEditPopUp } from '@/components/popup/GenderEditPopUp';
|
import { TypeEditPopUp } from '@/components/popup/GenderEditPopUp';
|
||||||
import { MediaEditPopUp } from '@/components/popup/TrackEditPopUp';
|
import { MediaEditPopUp } from '@/components/popup/MediaEditPopUp';
|
||||||
import { DisplaySeries } from '@/components/series/DisplaySeries';
|
import { DisplaySeries } from '@/components/series/DisplaySeries';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorModeValue } from '@/components/ui/color-mode';
|
||||||
import {
|
import {
|
||||||
|
@ -11,7 +11,7 @@ import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
|||||||
//import { useMediasOfAType } from '@/service/Media';
|
//import { useMediasOfAType } from '@/service/Media';
|
||||||
import { DisplayMediaFull } from '@/components/media/DisplayMediaFull';
|
import { DisplayMediaFull } from '@/components/media/DisplayMediaFull';
|
||||||
import { TypeEditPopUp } from '@/components/popup/GenderEditPopUp';
|
import { TypeEditPopUp } from '@/components/popup/GenderEditPopUp';
|
||||||
import { MediaEditPopUp } from '@/components/popup/TrackEditPopUp';
|
import { MediaEditPopUp } from '@/components/popup/MediaEditPopUp';
|
||||||
import { DisplaySeason } from '@/components/season/DisplaySeason';
|
import { DisplaySeason } from '@/components/season/DisplaySeason';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorModeValue } from '@/components/ui/color-mode';
|
||||||
import {
|
import {
|
||||||
@ -34,11 +34,11 @@ export const TypesSeriesDetailPage = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const onSelectSeasonItem = (mediaId: number) => {
|
const onSelectSeasonItem = (mediaId: number) => {
|
||||||
navigate(`/type/${typeId}/series/${seriesId}/season/${mediaId}`);
|
navigate(`/type/${typeId}/series/${seriesId}/season/${mediaId}`);
|
||||||
}
|
};
|
||||||
const onSelectItem = (mediaId: number) => {
|
const onSelectItem = (mediaId: number) => {
|
||||||
let currentPlay = 0;
|
let currentPlay = 0;
|
||||||
const listMediaId: number[] = [];
|
const listMediaId: number[] = [];
|
||||||
console.log(`select item:${mediaId}`);
|
console.log(`select item:${mediaId}`);
|
||||||
if (!videoWithType) {
|
if (!videoWithType) {
|
||||||
console.log('Fail to get Type...');
|
console.log('Fail to get Type...');
|
||||||
return;
|
return;
|
||||||
@ -108,8 +108,8 @@ export const TypesSeriesDetailPage = () => {
|
|||||||
>
|
>
|
||||||
{seasonOfSeriesId?.map((data) => (
|
{seasonOfSeriesId?.map((data) => (
|
||||||
<Box
|
<Box
|
||||||
key={data.id}
|
key={data.id}
|
||||||
width="full"
|
width="full"
|
||||||
maxWidth="calc(min(450px,80%))"
|
maxWidth="calc(min(450px,80%))"
|
||||||
height="150px"
|
height="150px"
|
||||||
border="1px"
|
border="1px"
|
||||||
@ -137,8 +137,8 @@ export const TypesSeriesDetailPage = () => {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</HStack>
|
</HStack>
|
||||||
<Box width="full" height="10px" background="red"/>
|
<Box width="full" height="10px" background="red" />
|
||||||
<HStack
|
<HStack
|
||||||
wrap="wrap"
|
wrap="wrap"
|
||||||
gap="20px"
|
gap="20px"
|
||||||
@ -148,7 +148,7 @@ export const TypesSeriesDetailPage = () => {
|
|||||||
>
|
>
|
||||||
{videoWithType?.map((data) => (
|
{videoWithType?.map((data) => (
|
||||||
<Box
|
<Box
|
||||||
key={data.id}
|
key={data.id}
|
||||||
width="200px"
|
width="200px"
|
||||||
height="300px"
|
height="300px"
|
||||||
border="1px"
|
border="1px"
|
||||||
|
@ -10,7 +10,7 @@ import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
|||||||
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { DisplayMediaListFull } from '@/components/media/DisplayMediaListFull';
|
import { DisplayMediaListFull } from '@/components/media/DisplayMediaListFull';
|
||||||
import { TypeEditPopUp } from '@/components/popup/GenderEditPopUp';
|
import { TypeEditPopUp } from '@/components/popup/GenderEditPopUp';
|
||||||
import { MediaEditPopUp } from '@/components/popup/TrackEditPopUp';
|
import { MediaEditPopUp } from '@/components/popup/MediaEditPopUp';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorModeValue } from '@/components/ui/color-mode';
|
||||||
import {
|
import {
|
||||||
useActivePlaylistService,
|
useActivePlaylistService,
|
||||||
@ -29,7 +29,11 @@ export const TypesSeriesSeasonDetailPage = () => {
|
|||||||
const { dataType } = useSpecificType(typeIdInt);
|
const { dataType } = useSpecificType(typeIdInt);
|
||||||
const { dataSeries } = useSpecificSeries(seriesIdInt);
|
const { dataSeries } = useSpecificSeries(seriesIdInt);
|
||||||
const { dataSeason } = useSpecificSeason(seasonIdInt);
|
const { dataSeason } = useSpecificSeason(seasonIdInt);
|
||||||
const { videoWithType: videos } = useTypeSeriesSeasonGetVideo(typeIdInt, seriesIdInt, seasonIdInt);
|
const { videoWithType: videos } = useTypeSeriesSeasonGetVideo(
|
||||||
|
typeIdInt,
|
||||||
|
seriesIdInt,
|
||||||
|
seasonIdInt
|
||||||
|
);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const onSelectItem = (mediaId: number) => {
|
const onSelectItem = (mediaId: number) => {
|
||||||
let currentPlay = 0;
|
let currentPlay = 0;
|
||||||
@ -107,7 +111,7 @@ export const TypesSeriesSeasonDetailPage = () => {
|
|||||||
{videos?.map((data) => (
|
{videos?.map((data) => (
|
||||||
<Box
|
<Box
|
||||||
key={data.id}
|
key={data.id}
|
||||||
width={{sm:"95%", base:"calc(max(300px,50%))"}}
|
width={{ sm: '95%', base: 'calc(max(300px,50%))' }}
|
||||||
height="60px"
|
height="60px"
|
||||||
border="1px"
|
border="1px"
|
||||||
borderColor="brand.900"
|
borderColor="brand.900"
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { Media, MediaResource } from '@/back-api';
|
import { Media, MediaResource, Season } from '@/back-api';
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { SessionServiceProps } from '@/service/session';
|
import { SessionServiceProps } from '@/service/session';
|
||||||
import { DataStoreType, useDataStore } from '@/utils/data-store';
|
import { DataStoreType, useDataStore } from '@/utils/data-store';
|
||||||
|
import { DataTools, TypeCheck } from '@/utils/data-tools';
|
||||||
|
|
||||||
|
import { useSeasonService } from './Season';
|
||||||
|
|
||||||
export type MediaServiceProps = {
|
export type MediaServiceProps = {
|
||||||
store: DataStoreType<Media>;
|
store: DataStoreType<Media>;
|
||||||
@ -42,3 +45,46 @@ export const useSpecificMedia = (id: number | undefined) => {
|
|||||||
return { isLoading: store.isLoading, dataMedia };
|
return { isLoading: store.isLoading, dataMedia };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useFilteredMedia = (typeId?: number, seriesId?: number) => {
|
||||||
|
const { store } = useMediaService();
|
||||||
|
const medias = useMemo(() => {
|
||||||
|
if (typeId === undefined) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return DataTools.getsWhere(
|
||||||
|
store.data,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
check: TypeCheck.EQUAL,
|
||||||
|
key: 'typeId',
|
||||||
|
value: typeId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: TypeCheck.EQUAL,
|
||||||
|
key: 'seriesId',
|
||||||
|
value: seriesId,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['name']
|
||||||
|
);
|
||||||
|
}, [store.data, typeId, seriesId]);
|
||||||
|
return { isLoading: store.isLoading, medias };
|
||||||
|
};
|
||||||
|
export type MediaExpandSeason = Media & {
|
||||||
|
season?: Season;
|
||||||
|
};
|
||||||
|
export const useMediaExpandSeason = (medias: Media[]) => {
|
||||||
|
const { store } = useSeasonService();
|
||||||
|
const mediasExpand = useMemo(() => {
|
||||||
|
const out: MediaExpandSeason[] = [];
|
||||||
|
medias.forEach((media) => {
|
||||||
|
if (media.seasonId === undefined) {
|
||||||
|
out.push(media);
|
||||||
|
}
|
||||||
|
const tmp = DataTools.get(store.data, media.seasonId, 'id');
|
||||||
|
out.push({ ...media, season: tmp });
|
||||||
|
});
|
||||||
|
return out;
|
||||||
|
}, [store.data, medias]);
|
||||||
|
return { isLoading: store.isLoading, mediasExpand };
|
||||||
|
};
|
||||||
|
@ -43,6 +43,9 @@ export const useOrderedSeries = (nameFilter?: string) => {
|
|||||||
const { store } = useSeriesService();
|
const { store } = useSeriesService();
|
||||||
const dataSeries = useMemo(() => {
|
const dataSeries = useMemo(() => {
|
||||||
let tmpData = store.data;
|
let tmpData = store.data;
|
||||||
|
if (tmpData == undefined) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
if (!isNullOrUndefined(nameFilter)) {
|
if (!isNullOrUndefined(nameFilter)) {
|
||||||
tmpData = DataTools.getNameLike(tmpData, nameFilter);
|
tmpData = DataTools.getNameLike(tmpData, nameFilter);
|
||||||
}
|
}
|
||||||
@ -60,7 +63,10 @@ export const useOrderedSeries = (nameFilter?: string) => {
|
|||||||
}, [store.data, nameFilter]);
|
}, [store.data, nameFilter]);
|
||||||
return { isLoading: store.isLoading, dataSeries };
|
return { isLoading: store.isLoading, dataSeries };
|
||||||
};
|
};
|
||||||
export const useOrderedSeriesWithType = (typeId?: Type["id"], nameFilter?: string) => {
|
export const useOrderedSeriesWithType = (
|
||||||
|
typeId?: Type['id'],
|
||||||
|
nameFilter?: string
|
||||||
|
) => {
|
||||||
const { store } = useSeriesService();
|
const { store } = useSeriesService();
|
||||||
const dataSeries = useMemo(() => {
|
const dataSeries = useMemo(() => {
|
||||||
let tmpData = store.data;
|
let tmpData = store.data;
|
||||||
@ -70,6 +76,7 @@ export const useOrderedSeriesWithType = (typeId?: Type["id"], nameFilter?: strin
|
|||||||
if (typeId === undefined) {
|
if (typeId === undefined) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
console.log('RRRRRRRRRRRRRRRRRRRRRRRegenarate ');
|
||||||
return DataTools.getsWhere(
|
return DataTools.getsWhere(
|
||||||
tmpData,
|
tmpData,
|
||||||
[
|
[
|
||||||
|
@ -84,10 +84,10 @@ export const useTypeCountVideo = (id?: number) => {
|
|||||||
return { isLoading: store.isLoading, countVideoWithType };
|
return { isLoading: store.isLoading, countVideoWithType };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useTypeGetVideo = (id?: number) => {
|
export const useTypeGetVideo = (typeId?: number) => {
|
||||||
const { store } = useMediaService();
|
const { store } = useMediaService();
|
||||||
const videoWithType = useMemo(() => {
|
const videoWithType = useMemo(() => {
|
||||||
if (id === undefined) {
|
if (typeId === undefined) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return DataTools.getsWhere(
|
return DataTools.getsWhere(
|
||||||
@ -96,7 +96,7 @@ export const useTypeGetVideo = (id?: number) => {
|
|||||||
{
|
{
|
||||||
check: TypeCheck.EQUAL,
|
check: TypeCheck.EQUAL,
|
||||||
key: 'typeId',
|
key: 'typeId',
|
||||||
value: id,
|
value: typeId,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
check: TypeCheck.EQUAL,
|
check: TypeCheck.EQUAL,
|
||||||
@ -111,7 +111,7 @@ export const useTypeGetVideo = (id?: number) => {
|
|||||||
],
|
],
|
||||||
['name']
|
['name']
|
||||||
);
|
);
|
||||||
}, [store.data, id]);
|
}, [store.data, typeId]);
|
||||||
return { isLoading: store.isLoading, videoWithType };
|
return { isLoading: store.isLoading, videoWithType };
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -154,7 +154,11 @@ export const useTypeSeriesGetVideo = (idType?: number, idSeries?: number) => {
|
|||||||
return { isLoading: store.isLoading, videoWithType };
|
return { isLoading: store.isLoading, videoWithType };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useTypeSeriesSeasonGetVideo = (idType?: number, idSeries?: number, idSeason?: number) => {
|
export const useTypeSeriesSeasonGetVideo = (
|
||||||
|
idType?: number,
|
||||||
|
idSeries?: number,
|
||||||
|
idSeason?: number
|
||||||
|
) => {
|
||||||
const { store } = useMediaService();
|
const { store } = useMediaService();
|
||||||
const videoWithType = useMemo(() => {
|
const videoWithType = useMemo(() => {
|
||||||
if (idType === undefined) {
|
if (idType === undefined) {
|
||||||
|
39
front/src/utils/debouncedCallback.ts
Normal file
39
front/src/utils/debouncedCallback.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
export const useDebouncedCallback = (
|
||||||
|
callback: (...args: any[]) => void,
|
||||||
|
delay: number = 2000
|
||||||
|
) => {
|
||||||
|
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
|
const debouncedFunction = useCallback(
|
||||||
|
(...args: any[]) => {
|
||||||
|
// Cancel timeout if it previously exist
|
||||||
|
if (timeoutRef.current) {
|
||||||
|
clearTimeout(timeoutRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
// start a new timer
|
||||||
|
timeoutRef.current = setTimeout(() => {
|
||||||
|
callback(...args);
|
||||||
|
}, delay);
|
||||||
|
},
|
||||||
|
[callback, delay]
|
||||||
|
);
|
||||||
|
|
||||||
|
return debouncedFunction;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDebounce = <T>(value: T, delay: number = 2000): T => {
|
||||||
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setDebouncedValue(value);
|
||||||
|
}, delay);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [value, delay]);
|
||||||
|
|
||||||
|
return debouncedValue;
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user