mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-25 11:43:17 +01:00
Upgrade ESLint and add useCallback (#914)
* Improvements: - Upgrade ESLint * Missing useCallback. Co-authored-by: Mikael Finstad <finstaden@gmail.com>
This commit is contained in:
parent
2568f5cd0f
commit
11502b84ed
20
src/App.jsx
20
src/App.jsx
@ -207,7 +207,7 @@ const App = memo(() => {
|
||||
}
|
||||
}, [detectedFileFormat, outFormatLocked, setOutFormatLocked]);
|
||||
|
||||
function setTimelineMode(newMode) {
|
||||
const setTimelineMode = useCallback((newMode) => {
|
||||
if (newMode === 'waveform') {
|
||||
setWaveformEnabled(v => !v);
|
||||
setThumbnailsEnabled(false);
|
||||
@ -215,7 +215,7 @@ const App = memo(() => {
|
||||
setThumbnailsEnabled(v => !v);
|
||||
setWaveformEnabled(false);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const toggleExportConfirmEnabled = useCallback(() => setExportConfirmEnabled((v) => !v), [setExportConfirmEnabled]);
|
||||
|
||||
@ -239,18 +239,18 @@ const App = memo(() => {
|
||||
|
||||
const getCurrentTime = useCallback(() => currentTimeRef.current, []);
|
||||
|
||||
function setCopyStreamIdsForPath(path, cb) {
|
||||
const setCopyStreamIdsForPath = useCallback((path, cb) => {
|
||||
setCopyStreamIdsByFile((old) => {
|
||||
const oldIds = old[path] || {};
|
||||
return ({ ...old, [path]: cb(oldIds) });
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const toggleRightBar = useCallback(() => setShowRightBar(v => !v), []);
|
||||
|
||||
const toggleCopyStreamId = useCallback((path, index) => {
|
||||
setCopyStreamIdsForPath(path, (old) => ({ ...old, [index]: !old[index] }));
|
||||
}, []);
|
||||
}, [setCopyStreamIdsForPath]);
|
||||
|
||||
const hideAllNotifications = hideNotifications === 'all';
|
||||
|
||||
@ -737,7 +737,7 @@ const App = memo(() => {
|
||||
});
|
||||
return newCopyStreamIds;
|
||||
});
|
||||
}, [copyAnyAudioTrack, filePath, mainStreams]);
|
||||
}, [copyAnyAudioTrack, filePath, mainStreams, setCopyStreamIdsForPath]);
|
||||
|
||||
const removeCutSegment = useCallback((index) => {
|
||||
if (cutSegments.length === 1 && cutSegments[0].start == null && cutSegments[0].end == null) return; // Initial segment
|
||||
@ -1400,7 +1400,7 @@ const App = memo(() => {
|
||||
resetState();
|
||||
throw err;
|
||||
}
|
||||
}, [resetState, html5ifyAndLoad, loadEdlFile, getEdlFilePath, getEdlFilePathOld, loadCutSegments, enableAskForImportChapters, autoLoadTimecode, outFormatLocked, showPreviewFileLoadedMessage, rememberConvertToSupportedFormat, setWorking]);
|
||||
}, [resetState, html5ifyAndLoad, loadEdlFile, getEdlFilePath, getEdlFilePathOld, loadCutSegments, enableAskForImportChapters, autoLoadTimecode, outFormatLocked, showPreviewFileLoadedMessage, rememberConvertToSupportedFormat, setWorking, setCopyStreamIdsForPath]);
|
||||
|
||||
const toggleHelp = useCallback(() => setHelpVisible(val => !val), []);
|
||||
const toggleSettings = useCallback(() => setSettingsVisible(val => !val), []);
|
||||
@ -1493,7 +1493,7 @@ const App = memo(() => {
|
||||
// console.log('streams', streams);
|
||||
setExternalStreamFiles(old => ({ ...old, [path]: { streams, formatData } }));
|
||||
setCopyStreamIdsForPath(path, () => fromPairs(streams.map(({ index }) => [index, true])));
|
||||
}, [externalStreamFiles]);
|
||||
}, [externalStreamFiles, setCopyStreamIdsForPath]);
|
||||
|
||||
const userOpenSingleFile = useCallback(async ({ path: pathIn, isLlcProject }) => {
|
||||
let path = pathIn;
|
||||
@ -1977,7 +1977,7 @@ const App = memo(() => {
|
||||
loadCutSegments, duration, checkFileOpened, loadMedia, fileFormat, reorderSegsByStartTime, closeFile, closeBatch, clearSegments, fixInvalidDuration, invertAllCutSegments,
|
||||
]);
|
||||
|
||||
async function showAddStreamSourceDialog() {
|
||||
const showAddStreamSourceDialog = useCallback(async () => {
|
||||
try {
|
||||
const { canceled, filePaths } = await dialog.showOpenDialog({ properties: ['openFile'] });
|
||||
if (canceled || filePaths.length < 1) return;
|
||||
@ -1985,7 +1985,7 @@ const App = memo(() => {
|
||||
} catch (err) {
|
||||
handleError(err);
|
||||
}
|
||||
}
|
||||
}, [addStreamSourceFile]);
|
||||
|
||||
useEffect(() => {
|
||||
async function onDrop(ev) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { memo } from 'react';
|
||||
import React, { memo, useCallback } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { Button, Select, CrossIcon } from 'evergreen-ui';
|
||||
import i18n from 'i18next';
|
||||
@ -52,39 +52,39 @@ const ExportConfirm = memo(({
|
||||
const isMov = ffmpegIsMov(outFormat);
|
||||
const isIpod = outFormat === 'ipod';
|
||||
|
||||
function onPreserveMovDataHelpPress() {
|
||||
const onPreserveMovDataHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Preserve all MOV/MP4 metadata tags (e.g. EXIF, GPS position etc.) from source file? Note that some players have trouble playing back files where all metadata is preserved, like iTunes and other Apple software') });
|
||||
}
|
||||
}, []);
|
||||
|
||||
function onMovFastStartHelpPress() {
|
||||
const onMovFastStartHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Enable this to allow faster playback of the resulting file. This may cause processing to take a little longer') });
|
||||
}
|
||||
}, []);
|
||||
|
||||
function onOutFmtHelpPress() {
|
||||
const onOutFmtHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Defaults to same format as input file. You can losslessly change the file format (container) of the file with this option. Not all formats support all codecs. Matroska/MP4/MOV support the most common codecs. Sometimes it\'s even impossible to export to the same output format as input.') });
|
||||
}
|
||||
}, []);
|
||||
|
||||
function onKeyframeCutHelpPress() {
|
||||
const onKeyframeCutHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('With "keyframe cut", we will cut at the nearest keyframe before the desired start cutpoint. This is recommended for most files. With "Normal cut" you may have to manually set the cutpoint a few frames before the next keyframe to achieve a precise cut') });
|
||||
}
|
||||
}, []);
|
||||
|
||||
function onTracksHelpPress() {
|
||||
const onTracksHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Not all formats support all track types, and LosslessCut is unable to properly cut some track types, so you may have to sacrifice some tracks by disabling them in order to get correct result.') });
|
||||
}
|
||||
}, []);
|
||||
|
||||
function onSegmentsToChaptersHelpPress() {
|
||||
const onSegmentsToChaptersHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('When merging, do you want to create chapters in the merged file, according to the cut segments? NOTE: This may dramatically increase processing time') });
|
||||
}
|
||||
}, []);
|
||||
|
||||
function onPreserveMetadataOnMergeHelpPress() {
|
||||
const onPreserveMetadataOnMergeHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('When merging, do you want to preserve metadata from your original file? NOTE: This may dramatically increase processing time') });
|
||||
}
|
||||
}, []);
|
||||
|
||||
function onOutSegTemplateHelpPress() {
|
||||
const onOutSegTemplateHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('You can customize the file name of the output segment(s) using special variables.') });
|
||||
}
|
||||
}, []);
|
||||
|
||||
function onAvoidNegativeTsHelpPress() {
|
||||
const onAvoidNegativeTsHelpPress = useCallback(() => {
|
||||
// https://ffmpeg.org/ffmpeg-all.html#Format-Options
|
||||
const texts = {
|
||||
make_non_negative: i18n.t('Shift timestamps to make them non-negative. Also note that this affects only leading negative timestamps, and not non-monotonic negative timestamps.'),
|
||||
@ -93,7 +93,7 @@ const ExportConfirm = memo(({
|
||||
disabled: i18n.t('Disables shifting of timestamp.'),
|
||||
};
|
||||
toast.fire({ icon: 'info', timer: 10000, text: `${avoidNegativeTs}: ${texts[avoidNegativeTs]}` });
|
||||
}
|
||||
}, [avoidNegativeTs]);
|
||||
|
||||
const outSegTemplateHelpIcon = <HelpIcon onClick={onOutSegTemplateHelpPress} />;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { memo } from 'react';
|
||||
import React, { memo, useCallback } from 'react';
|
||||
import { Select } from 'evergreen-ui';
|
||||
import { motion } from 'framer-motion';
|
||||
import { FaYinYang } from 'react-icons/fa';
|
||||
@ -14,14 +14,14 @@ const zoomOptions = Array(13).fill().map((unused, z) => 2 ** z);
|
||||
const LeftMenu = memo(({ zoom, setZoom, invertCutSegments, setInvertCutSegments, toggleComfortZoom, simpleMode, toggleSimpleMode }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
function onYinYangClick() {
|
||||
const onYinYangClick = useCallback(() => {
|
||||
setInvertCutSegments(v => {
|
||||
const newVal = !v;
|
||||
if (newVal) toast.fire({ title: t('When you export, selected segments on the timeline will be REMOVED - the surrounding areas will be KEPT') });
|
||||
else toast.fire({ title: t('When you export, selected segments on the timeline will be KEPT - the surrounding areas will be REMOVED.') });
|
||||
return newVal;
|
||||
});
|
||||
}
|
||||
}, [setInvertCutSegments, t]);
|
||||
|
||||
return (
|
||||
<div className="no-user-select" style={{ padding: '.3em', display: 'flex', alignItems: 'center' }}>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { memo, useMemo, useRef } from 'react';
|
||||
import React, { memo, useMemo, useRef, useCallback } from 'react';
|
||||
import prettyMs from 'pretty-ms';
|
||||
import { FaSave, FaPlus, FaMinus, FaTag, FaSortNumericDown, FaAngleRight, FaCheck, FaTimes } from 'react-icons/fa';
|
||||
import { AiOutlineSplitCells } from 'react-icons/ai';
|
||||
@ -130,10 +130,10 @@ const SegmentList = memo(({
|
||||
|
||||
const sortableList = outSegments.map((seg) => ({ id: seg.segId, seg }));
|
||||
|
||||
function setSortableList(newList) {
|
||||
const setSortableList = useCallback((newList) => {
|
||||
if (isEqual(outSegments.map((s) => s.segId), newList.map((l) => l.id))) return; // No change
|
||||
updateSegOrders(newList.map((list) => list.id));
|
||||
}
|
||||
}, [outSegments, updateSegOrders]);
|
||||
|
||||
let headerText = t('Segments to export:');
|
||||
if (outSegments.length === 0) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { memo } from 'react';
|
||||
import React, { memo, useCallback } from 'react';
|
||||
import { FaYinYang } from 'react-icons/fa';
|
||||
import { Button, Table, NumericalIcon, KeyIcon, FolderCloseIcon, DocumentIcon, TimeIcon, Checkbox, Select } from 'evergreen-ui';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -20,11 +20,11 @@ const Settings = memo(({
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
const KeyCell = (props) => <Table.TextCell textProps={{ whiteSpace: 'auto' }} {...props} />;
|
||||
|
||||
function onLangChange(e) {
|
||||
const onLangChange = useCallback((e) => {
|
||||
const { value } = e.target;
|
||||
const l = value !== '' ? value : undefined;
|
||||
setLanguage(l);
|
||||
}
|
||||
}, [setLanguage]);
|
||||
|
||||
// https://www.electronjs.org/docs/api/locales
|
||||
// See i18n.js
|
||||
|
@ -45,11 +45,11 @@ const SortableFiles = memo(({
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
function onSortClick() {
|
||||
const onSortClick = useCallback(() => {
|
||||
const newSortDesc = sortDesc == null ? false : !sortDesc;
|
||||
setItems(orderBy(items, undefined, [newSortDesc ? 'desc' : 'asc']));
|
||||
setSortDesc(newSortDesc);
|
||||
}
|
||||
}, [items, sortDesc]);
|
||||
|
||||
return (
|
||||
<div style={{ textAlign: 'left' }}>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { memo, useState, useMemo } from 'react';
|
||||
import React, { memo, useState, useMemo, useCallback } from 'react';
|
||||
|
||||
import { FaCheckCircle, FaPaperclip, FaVideo, FaVideoSlash, FaFileImport, FaVolumeUp, FaVolumeMute, FaBan, FaFileExport } from 'react-icons/fa';
|
||||
import { GoFileBinary } from 'react-icons/go';
|
||||
@ -23,13 +23,13 @@ const TagEditor = memo(({ existingTags, customTags, onTagChange, onTagReset }) =
|
||||
const [editingTagVal, setEditingTagVal] = useState();
|
||||
const [newTag, setNewTag] = useState();
|
||||
|
||||
const mergedTags = { ...existingTags, ...customTags, ...(newTag ? { [newTag]: '' } : {}) };
|
||||
const mergedTags = useMemo(() => ({ ...existingTags, ...customTags, ...(newTag ? { [newTag]: '' } : {}) }), [customTags, existingTags, newTag]);
|
||||
|
||||
function onResetClick() {
|
||||
const onResetClick = useCallback(() => {
|
||||
onTagReset(editingTag);
|
||||
setEditingTag();
|
||||
setNewTag();
|
||||
}
|
||||
}, [editingTag, onTagReset]);
|
||||
|
||||
function onEditClick(tag) {
|
||||
if (newTag) {
|
||||
@ -54,13 +54,13 @@ const TagEditor = memo(({ existingTags, customTags, onTagChange, onTagReset }) =
|
||||
onEditClick();
|
||||
}
|
||||
|
||||
async function onAddPress() {
|
||||
const onAddPress = useCallback(async () => {
|
||||
const tag = await askForMetadataKey();
|
||||
if (!tag || Object.keys(mergedTags).includes(tag)) return;
|
||||
setEditingTag(tag);
|
||||
setEditingTagVal('');
|
||||
setNewTag(tag);
|
||||
}
|
||||
}, [mergedTags]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -103,16 +103,16 @@ const EditFileDialog = memo(({ editingFile, externalFiles, mainFileFormatData, m
|
||||
const existingTags = formatData.tags || {};
|
||||
const customTags = customTagsByFile[editingFile] || {};
|
||||
|
||||
function onTagChange(tag, value) {
|
||||
const onTagChange = useCallback((tag, value) => {
|
||||
setCustomTagsByFile((old) => ({ ...old, [editingFile]: { ...old[editingFile], [tag]: value } }));
|
||||
}
|
||||
}, [editingFile, setCustomTagsByFile]);
|
||||
|
||||
function onTagReset(tag) {
|
||||
const onTagReset = useCallback((tag) => {
|
||||
setCustomTagsByFile((old) => {
|
||||
const { [tag]: deleted, ...rest } = old[editingFile] || {};
|
||||
return { ...old, [editingFile]: rest };
|
||||
});
|
||||
}
|
||||
}, [editingFile, setCustomTagsByFile]);
|
||||
|
||||
return <TagEditor existingTags={existingTags} customTags={customTags} onTagChange={onTagChange} onTagReset={onTagReset} />;
|
||||
});
|
||||
@ -132,7 +132,7 @@ const EditStreamDialog = memo(({ editingStream: { streamId: editingStreamId, pat
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
function onTagChange(tag, value) {
|
||||
const onTagChange = useCallback((tag, value) => {
|
||||
setCustomTagsByStreamId((old) => ({
|
||||
...old,
|
||||
[editingFile]: {
|
||||
@ -143,9 +143,9 @@ const EditStreamDialog = memo(({ editingStream: { streamId: editingStreamId, pat
|
||||
},
|
||||
},
|
||||
}));
|
||||
}
|
||||
}, [editingFile, editingStreamId, setCustomTagsByStreamId]);
|
||||
|
||||
function onTagReset(tag) {
|
||||
const onTagReset = useCallback((tag) => {
|
||||
setCustomTagsByStreamId((old) => {
|
||||
const { [tag]: deleted, ...rest } = (old[editingFile] || {})[editingStreamId] || {};
|
||||
|
||||
@ -157,9 +157,9 @@ const EditStreamDialog = memo(({ editingStream: { streamId: editingStreamId, pat
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
}, [editingFile, editingStreamId, setCustomTagsByStreamId]);
|
||||
|
||||
function onCoverArtChange(e) {
|
||||
const onCoverArtChange = useCallback((e) => {
|
||||
const newDispositions = dispositionOptions.includes(e.target.value) ? {
|
||||
[e.target.value]: 1,
|
||||
} : undefined;
|
||||
@ -173,7 +173,7 @@ const EditStreamDialog = memo(({ editingStream: { streamId: editingStreamId, pat
|
||||
[editingStreamId]: newDispositions,
|
||||
},
|
||||
}));
|
||||
}
|
||||
}, [editingFile, editingStreamId, setDispositionByStreamId]);
|
||||
|
||||
if (!stream) return null;
|
||||
|
||||
|
@ -52,15 +52,15 @@ const OutSegTemplateEditor = memo(({ helpIcon, outSegTemplate, setOutSegTemplate
|
||||
if (validText != null) setOutSegTemplate(validText);
|
||||
}, [validText, setOutSegTemplate]);
|
||||
|
||||
function reset() {
|
||||
const reset = useCallback(() => {
|
||||
setOutSegTemplate(defaultOutSegTemplate);
|
||||
setText(defaultOutSegTemplate);
|
||||
}
|
||||
}, [setOutSegTemplate]);
|
||||
|
||||
function onToggleClick() {
|
||||
const onToggleClick = useCallback(() => {
|
||||
if (!shown) setShown(true);
|
||||
else if (error == null) setShown(false);
|
||||
}
|
||||
}, [error, shown]);
|
||||
|
||||
const onTextChange = useCallback((e) => setText(e.target.value), []);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { Checkbox, RadioGroup, Paragraph } from 'evergreen-ui';
|
||||
import Swal from 'sweetalert2';
|
||||
import i18n from 'i18next';
|
||||
@ -65,14 +65,14 @@ export async function askForHtml5ifySpeed({ allowedOptions, showRemember, initia
|
||||
const Html = () => {
|
||||
const [option, setOption] = useState(selectedOption);
|
||||
const [remember, setRemember] = useState(rememberChoice);
|
||||
function onOptionChange(e) {
|
||||
const onOptionChange = useCallback((e) => {
|
||||
selectedOption = e.target.value;
|
||||
setOption(selectedOption);
|
||||
}
|
||||
function onRememberChange(e) {
|
||||
}, []);
|
||||
const onRememberChange = useCallback((e) => {
|
||||
rememberChoice = e.target.checked;
|
||||
setRemember(rememberChoice);
|
||||
}
|
||||
}, []);
|
||||
return (
|
||||
<div style={{ textAlign: 'left' }}>
|
||||
<Paragraph>{i18n.t('These options will let you convert files to a format that is supported by the player. You can try different options and see which works with your file. Note that the conversion is for preview only. When you run an export, the output will still be lossless with full quality')}</Paragraph>
|
||||
|
Loading…
Reference in New Issue
Block a user