import { useCallback, useState } from 'react'; import { Button, Flex, Input, Table, Text, } from '@chakra-ui/react'; import { LuTrash } from 'react-icons/lu'; import { MdCloudUpload } from 'react-icons/md'; import { Album, AlbumResource, Artist, ArtistResource, Gender, GenderResource, RestErrorResponse, Track, TrackResource, } from '@/back-api'; import { PageLayout } from '@/components/Layout/PageLayout'; import { TopBar } from '@/components/TopBar/TopBar'; import { FormSelect } from '@/components/form/FormSelect'; import { useFormidable } from '@/components/form/Formidable'; import { PopUpUploadProgress } from '@/components/popup/PopUpUploadProgress'; import { useAlbumService, useOrderedAlbums } from '@/service/Album'; import { useArtistService, useOrderedArtists } from '@/service/Artist'; import { useGenderService, useOrderedGenders } from '@/service/Gender'; import { useServiceContext } from '@/service/ServiceContext'; import { useTrackService } from '@/service/Track'; import { isNullOrUndefined } from '@/utils/validator'; export class ElementList { constructor( public id?: number, public label?: string ) { // nothing to do. } } export class FileParsedElement { public isSended: boolean = false; public nameDetected: boolean = false; public trackIdDetected: boolean = false; constructor( public uniqueId: number, public file: File, public title: string, public artist?: string, public album?: string, public trackId?: number ) { console.log(`Unique element: ${uniqueId}`); // nothing to do. } } export class FileFailParsedElement { constructor( public uniqueId: number, public file: File, public reason: string ) { console.log(`Unique element2: ${uniqueId}`); // nothing to do. } } type FormInsertData = { genderId?: number; artistId?: number; titleAlbum?: string; }; export const AddPage = () => { const [parsedElement, setParsedElement] = useState([]); const [parsedFailedElement, setParsedFailedElement] = useState< FileFailParsedElement[] | undefined >(undefined); const [needSend, setNeedSend] = useState(false); // list of all files already registered in the bdd to compare with the current list of files. const [listFileInBdd, setListFileInBdd] = useState( undefined ); const { dataGenders } = useOrderedGenders(); const { dataArtist } = useOrderedArtists(); const { dataAlbums } = useOrderedAlbums(); const { store: storeGender } = useGenderService(); const { store: storeArtist } = useArtistService(); const { store: storeAlbum } = useAlbumService(); const { store: storeTrack } = useTrackService(); const { session } = useServiceContext(); const form = useFormidable({}); const updateNeedSend = () => { if (parsedElement.length === 0) { setNeedSend(false); return; } let tmp = true; for (let iii = 0; iii < parsedElement.length; iii++) { if ( isNullOrUndefined(parsedElement[iii].title) || parsedElement[iii].title === '' ) { tmp = false; } } setNeedSend(tmp); }; const onTitle = (data: FileParsedElement, value: any): void => { data.title = value; setParsedElement([...parsedElement]); updateNeedSend(); }; const removeElementFromList = (data: FileParsedElement, value: any): void => { const parsedElementTmp = [...parsedElement]; for (let iii = 0; iii < parsedElementTmp.length; iii++) { if (parsedElementTmp[iii] === data) { parsedElementTmp.splice(iii, 1); break; } } setParsedElement(parsedElementTmp); setParsedFailedElement((previous) => [ ...(previous ?? []), new FileFailParsedElement( previous?.length ?? 0, data.file, 'Removed by user.' ), ]); updateNeedSend(); }; const onTrackId = (data: FileParsedElement, value: any): void => { data.trackId = value; setParsedElement([...parsedElement]); updateNeedSend(); }; const clearData = () => { setParsedElement([]); setParsedFailedElement(undefined); setListFileInBdd(undefined); setSuggestedArtist(undefined); setSuggestedAlbum(undefined); }; const addFileWithMetaData = (file: File, id: number) => { // parsedElement: FileParsedElement[] = []; let artist: string | undefined = undefined; let album: string | undefined = undefined; let trackIdNumber: number | undefined = undefined; let title: string = ''; form.restoreValues(); console.log(`select file ${file.name}`); let tmpName = file.name.replace(/[ \t]*-[ \t]*/g, '-'); //tmpName = tmpName.replace(/_/g, '-'); //tmpName = tmpName.replace(/--/g, '-'); console.log(`select file ${tmpName}`); const splitElement = tmpName.split('~'); if (splitElement.length > 1) { artist = splitElement[0]; tmpName = tmpName.substring(artist.length + 1); } const splitElement2 = tmpName.split('#'); if (splitElement2.length > 1) { album = splitElement2[0]; tmpName = tmpName.substring(album.length + 1); } //console.log("ploppppp " + tmpName); const splitElement3 = tmpName.split('-'); if (splitElement3.length > 1) { trackIdNumber = parseInt(splitElement3[0], 10); tmpName = tmpName.substring(splitElement3[0].length + 1); } //console.log("KKKppppp " + tmpName); //console.log(" ===> " + splitElement3[0]); title = tmpName; if (trackIdNumber && isNaN(trackIdNumber)) { trackIdNumber = undefined; } // remove extension title = title.replace(new RegExp('\\.(webm|WEBM|Webm)'), ''); let tmp = new FileParsedElement( id, file, title, artist, album, trackIdNumber ); console.log(`==>${JSON.stringify(tmp)}`); // add it in the list. return tmp; }; const [suggestedArtist, setSuggestedArtist] = useState( undefined ); const [suggestedAlbum, setSuggestedAlbum] = useState( undefined ); const onChangeFile = (value: any): void => { clearData(); const parsedElementTmp: FileParsedElement[] = []; const parsedFailedElementTmp: FileFailParsedElement[] = []; for (let iii = 0; iii < value.target.files?.length; iii++) { parsedElementTmp.push(addFileWithMetaData(value.target.files[iii], iii)); } // check if all global parameters are generic: if (parsedElementTmp.length === 0) { updateNeedSend(); return; } // clean different artist: for (let iii = 1; iii < parsedElementTmp.length; iii++) { console.log( `check artist [${iii + 1}/${parsedElementTmp.length}] '${parsedElementTmp[0].artist} !== ${parsedElementTmp[iii].artist}'` ); if (parsedElementTmp[0].artist !== parsedElementTmp[iii].artist) { parsedFailedElementTmp.push( new FileFailParsedElement( parsedFailedElementTmp.length, parsedElementTmp[iii].file, 'Remove from list due to wrong artist value' ) ); console.log( `Remove from list (!= artist) : [${iii + 1}/${parsedElementTmp.length}] '${parsedElementTmp[iii].file.name}'` ); parsedElementTmp.splice(iii, 1); iii--; } } // clean different album: for (let iii = 1; iii < parsedElementTmp.length; iii++) { console.log( `check album [${iii + 1}/${parsedElementTmp.length}] '${parsedElementTmp[0].album} !== ${parsedElementTmp[iii].album}'` ); if (parsedElementTmp[0].album !== parsedElementTmp[iii].album) { parsedFailedElementTmp.push( new FileFailParsedElement( parsedFailedElementTmp.length, parsedElementTmp[iii].file, 'Remove from list due to wrong album value' ) ); console.log( `Remove from list (!= album) : [${iii + 1}/${parsedElementTmp.length}] '${parsedElementTmp[iii].file.name}'` ); parsedElementTmp.splice(iii, 1); iii--; } } setParsedElement(parsedElementTmp); setParsedFailedElement(parsedFailedElementTmp); console.log(`check : ${JSON.stringify(parsedElementTmp[0])}`); // find artistId: console.log(`try find artist : ${parsedElementTmp[0].artist}`); let artistFound = false; dataArtist.forEach((data) => { if ( data.name?.toLowerCase() === parsedElementTmp[0].artist?.toLowerCase() ) { console.log(` find artist : ${data.id}`); form.setValues({ artistId: data.id }); artistFound = true; } }); if (!artistFound) { console.log(` set Suggested artist : ${parsedElementTmp[0].artist}`); setSuggestedArtist(parsedElementTmp[0].artist); } else { setSuggestedArtist(undefined); } // try to find album console.log(`try find album : ${parsedElementTmp[0].album}`); let albumFound = false; dataAlbums.forEach((data) => { if ( data.name?.toLowerCase() === parsedElementTmp[0].album?.toLowerCase() ) { console.log(` find album : ${data.id}`); form.setValues({ albumId: data.id }); albumFound = true; } }); if (!albumFound) { console.log(` set Suggested album : ${parsedElementTmp[0].album}`); setSuggestedAlbum(parsedElementTmp[0].album); } updateNeedSend(); }; const [indexUpload, setIndexUpload] = useState(undefined); const [listValues, setListValues] = useState([]); const [currentPosition, setCurrentPosition] = useState(0); const [totalPosition, setTotalPosition] = useState(0); const [uploadError, setUploadError] = useState(undefined); const [isFinishedUpload, setIsFinishedUpload] = useState(false); const progressUpload = useCallback( (count: number, total: number) => { setTotalPosition(total); setCurrentPosition(count); }, [setTotalPosition, setCurrentPosition] ); const uploadNext = useCallback( (index: number = 0): void => { if (parsedElement.length <= index) { console.log('end of upload'); setIsFinishedUpload(true); return; } setIndexUpload(index); console.log( `Start upload of file: ${index}: ${parsedElement[index].title}` ); storeTrack .update( TrackResource.uploadTrack({ restConfig: session.getRestConfig(), data: { title: parsedElement[index].title, file: parsedElement[index].file, albumId: form.values['albumId'] ?? undefined, artistId: form.values['artistId'] ?? undefined, genderId: form.values['genderId'] ?? undefined, trackId: parsedElement[index].trackId ?? undefined, }, callbacks: { progressUpload: progressUpload, }, }) ) .then((data: Track) => { // element sended good // Send next ... uploadNext(index + 1); }) .catch((error: RestErrorResponse) => { // TODO: manage error console.log(`element error: ${JSON.stringify(error, null, 2)}`); setUploadError(JSON.stringify(error, null, 2)); }); }, [setUploadError, setIndexUpload, storeTrack, parsedElement] ); const sendFile = (): void => { console.log(`Send file requested ... ${parsedElement.length}`); setUploadError(undefined); setIsFinishedUpload(false); setListValues(parsedElement.map((element) => element.file.name)); uploadNext(); }; function onUploadAbort(): void { setIndexUpload(undefined); } function OnUploadClose(): void { setIndexUpload(undefined); } const addNewGender = (data: string): Promise => { return storeGender.update( GenderResource.post({ restConfig: session.getRestConfig(), data: { name: data, }, }) ); }; const addNewArtist = (data: string): Promise => { return storeArtist.update( ArtistResource.post({ restConfig: session.getRestConfig(), data: { name: data, }, }) ); }; const addNewAlbum = (data: string): Promise => { return storeAlbum.update( AlbumResource.post({ restConfig: session.getRestConfig(), data: { name: data, }, }) ); }; return ( <> format: The format of the media permit to automatic find meta-data:
Artist~album#idTrack-my name of my media.webm
example: Clarika~Moi En Mieux#22-des bulles.webm
Media:
{parsedElement && parsedElement.length !== 0 && ( <> Meta-data: track ID Title actions {parsedElement.map((data) => ( onTrackId(data, e.target.value)} backgroundColor={ data.trackIdDetected === true ? 'darkred' : undefined } /> onTitle(data, e.target.value)} backgroundColor={ data.title === '' ? 'darkred' : undefined } /> {data.nameDetected === true && ( <>
^^^This title already exist !!! )}
))}
)} {listFileInBdd && ( track ID Title actions {listFileInBdd.map((data) => ( {data.trackId} {data.title} ))} )} {parsedFailedElement && ( <> Rejected: file Reason {parsedFailedElement.map((data) => ( {data.file.name} {data.reason} ))} )}
{indexUpload !== undefined && ( )}
); };