1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-22 10:22:31 +01:00

enable exactOptionalPropertyTypes

This commit is contained in:
Mikael Finstad 2024-03-03 20:35:04 +08:00
parent 41c18546c2
commit cb5a8c2c85
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26
21 changed files with 47 additions and 37 deletions

View File

@ -111,7 +111,7 @@ function App() {
const [ffmpegCommandLog, setFfmpegCommandLog] = useState<FfmpegCommandLog>([]);
const [previewFilePath, setPreviewFilePath] = useState<string>();
const [working, setWorkingState] = useState<{ text: string, abortController?: AbortController }>();
const [working, setWorkingState] = useState<{ text: string, abortController?: AbortController | undefined }>();
const [usingDummyVideo, setUsingDummyVideo] = useState(false);
const [playing, setPlaying] = useState(false);
const [compatPlayerEventId, setCompatPlayerEventId] = useState(0);
@ -879,6 +879,7 @@ function App() {
setTotalProgress();
}
// @ts-expect-error todo
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (failedFiles.length > 0) toast.fire({ title: `${i18n.t('Failed to convert files:')} ${failedFiles.join(' ')}`, timer: null as any as undefined, showConfirmButton: true });
} catch (err) {

View File

@ -11,15 +11,15 @@ const { createMediaSourceStream, readOneJpegFrame } = remote.require('./compatPl
async function startPlayback({ path, video, videoStreamIndex, audioStreamIndex, seekTo, signal, playSafe, onCanPlay, getTargetTime, size, fps }: {
path: string,
video: HTMLVideoElement,
videoStreamIndex?: number,
audioStreamIndex?: number,
videoStreamIndex?: number | undefined,
audioStreamIndex?: number | undefined,
seekTo: number,
signal: AbortSignal,
playSafe: () => void,
onCanPlay: () => void,
getTargetTime: () => number,
size?: number,
fps?: number,
size?: number | undefined,
fps?: number | undefined,
}) {
let canPlay = false;
let bufferEndTime: number | undefined;

View File

@ -11,7 +11,7 @@ const CaptureFormatButton = memo(({ showIcon = false, ...props }: { showIcon?: b
const { captureFormat, toggleCaptureFormat } = useUserSettings();
return (
<Button
iconBefore={showIcon ? <FaImage /> : undefined}
iconBefore={showIcon ? <FaImage /> : null}
title={t('Capture frame format')}
onClick={withBlur(toggleCaptureFormat)}
// eslint-disable-next-line react/jsx-props-no-spreading

View File

@ -1,12 +1,12 @@
import { CSSProperties, memo, useCallback } from 'react';
import { memo, useCallback } from 'react';
import { FaClipboard } from 'react-icons/fa';
import { useTranslation } from 'react-i18next';
import { motion, useAnimation } from 'framer-motion';
import { MotionStyle, motion, useAnimation } from 'framer-motion';
const electron = window.require('electron');
const { clipboard } = electron;
const CopyClipboardButton = memo(({ text, style }: { text: string, style?: CSSProperties }) => {
const CopyClipboardButton = memo(({ text, style }: { text: string, style?: MotionStyle }) => {
const { t } = useTranslation();
const animation = useAnimation();

View File

@ -32,7 +32,7 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate
const [text, setText] = useState(outSegTemplate);
const [debouncedText] = useDebounce(text, 500);
const [validText, setValidText] = useState<string>();
const [outSegProblems, setOutSegProblems] = useState<{ error?: string, sameAsInputFileNameWarning?: boolean }>({ error: undefined, sameAsInputFileNameWarning: false });
const [outSegProblems, setOutSegProblems] = useState<{ error?: string | undefined, sameAsInputFileNameWarning?: boolean | undefined }>({ error: undefined, sameAsInputFileNameWarning: false });
const [outSegFileNames, setOutSegFileNames] = useState<string[]>();
const [shown, setShown] = useState<boolean>();
const inputRef = useRef<HTMLInputElement>(null);

View File

@ -16,7 +16,7 @@ function renderFormatOptions(formats) {
}
const OutputFormatSelect = memo(({ style, detectedFileFormat, fileFormat, onOutputFormatUserChange }: {
style: CSSProperties, detectedFileFormat?: string, fileFormat?: string, onOutputFormatUserChange: (a: string) => void,
style: CSSProperties, detectedFileFormat?: string | undefined, fileFormat?: string | undefined, onOutputFormatUserChange: (a: string) => void,
}) => {
const commonVideoAudioFormatsExceptDetectedFormat = useMemo(() => commonVideoAudioFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]);
const commonAudioFormatsExceptDetectedFormat = useMemo(() => commonAudioFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]);

View File

@ -17,12 +17,12 @@ const PlaybackStreamSelector = memo(({
subtitleStreams,
videoStreams,
audioStreams,
activeSubtitleStreamIndex?: number,
activeVideoStreamIndex?: number,
activeAudioStreamIndex?: number,
onActiveSubtitleChange: (a?: number) => void,
onActiveVideoStreamChange: (a?: number) => void,
onActiveAudioStreamChange: (a?: number) => void,
activeSubtitleStreamIndex?: number | undefined,
activeVideoStreamIndex?: number | undefined,
activeAudioStreamIndex?: number | undefined,
onActiveSubtitleChange: (a?: number | undefined) => void,
onActiveVideoStreamChange: (a?: number | undefined) => void,
onActiveAudioStreamChange: (a?: number | undefined) => void,
}) => {
const [controlVisible, setControlVisible] = useState(false);
const timeoutRef = useRef<number>();

View File

@ -5,7 +5,7 @@ import useUserSettings from '../hooks/useUserSettings';
import { SegmentBase } from '../types';
const SegmentCutpointButton = ({ currentCutSeg, side, Icon, onClick, title, style }: {
currentCutSeg: SegmentBase, side: 'start' | 'end', Icon, onClick?: () => void, title?: string, style?: CSSProperties
currentCutSeg: SegmentBase, side: 'start' | 'end', Icon, onClick?: (() => void) | undefined, title?: string | undefined, style?: CSSProperties | undefined
}) => {
const { darkMode } = useUserSettings();
const { getSegColor } = useSegColors();

View File

@ -9,7 +9,7 @@ import loadingLottie from '../7077-magic-flow.json';
const Working = memo(({ text, cutProgress, onAbortClick }: {
text: string, cutProgress?: number, onAbortClick: () => void
text: string, cutProgress?: number | undefined, onAbortClick: () => void
}) => (
<div style={{ position: 'absolute', bottom: 0, top: 0, left: 0, right: 0, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<motion.div

View File

@ -12,7 +12,7 @@ const ReactSwal = withReactContent(Swal);
// eslint-disable-next-line import/prefer-default-export
export async function askForHtml5ifySpeed({ allowedOptions, showRemember, initialOption }: {
allowedOptions: Html5ifyMode[], showRemember?: boolean, initialOption?: Html5ifyMode
allowedOptions: Html5ifyMode[], showRemember?: boolean | undefined, initialOption?: Html5ifyMode | undefined
}) {
const availOptions: Record<Html5ifyMode, string> = {
fastest: i18n.t('Fastest: FFmpeg-assisted playback'),

View File

@ -19,7 +19,8 @@ const { dialog } = window.require('@electron/remote');
const ReactSwal = withReactContent(Swal);
export async function promptTimeOffset({ initialValue, title, text }: { initialValue?: string, title: string, text?: string }) {
export async function promptTimeOffset({ initialValue, title, text }: { initialValue?: string | undefined, title: string, text?: string | undefined }) {
// @ts-expect-error todo
const { value } = await Swal.fire({
title,
text,
@ -44,6 +45,7 @@ export async function promptTimeOffset({ initialValue, title, text }: { initialV
export const showOpenDialog = async ({
filters = isWindows ? [{ name: i18n.t('All Files'), extensions: ['*'] }] : undefined,
...props
// @ts-expect-error todo
}) => dialog.showOpenDialog({ ...props, filters });
export async function askForYouTubeInput() {
@ -468,6 +470,7 @@ export async function showExportFailedDialog({ fileFormat, safeOutputFileName })
</div>
);
// @ts-expect-error todo
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { value } = await ReactSwal.fire({ title: i18n.t('Unable to export this file'), html, timer: null as any as undefined, showConfirmButton: true, showCancelButton: true, cancelButtonText: i18n.t('OK'), confirmButtonText: i18n.t('Report'), reverseButtons: true, focusCancel: true });
return value;
@ -489,6 +492,7 @@ export async function showConcatFailedDialog({ fileFormat }) {
</div>
);
// @ts-expect-error todo
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { value } = await ReactSwal.fire({ title: i18n.t('Unable to merge files'), html, timer: null as any as undefined, showConfirmButton: true, showCancelButton: true, cancelButtonText: i18n.t('OK'), confirmButtonText: i18n.t('Report'), reverseButtons: true, focusCancel: true });
return value;
@ -569,6 +573,7 @@ export function showJson5Dialog({ title, json }) {
export async function openDirToast({ filePath, text, html, ...props }: SweetAlertOptions & { filePath: string }) {
const swal = text ? toast : ReactSwal;
// @ts-expect-error todo
const { value } = await swal.fire({
...swalToastOptions,
showConfirmButton: true,
@ -583,6 +588,7 @@ export async function openDirToast({ filePath, text, html, ...props }: SweetAler
}
const UnorderedList = ({ children }) => <ul style={{ paddingLeft: '1em' }}>{children}</ul>;
// @ts-expect-error todo
const ListItem = ({ icon: Icon, iconColor, children, style }: { icon: IconComponent, iconColor?: string, children: ReactNode, style?: CSSProperties }) => <li style={{ listStyle: 'none', ...style }}>{Icon && <Icon color={iconColor} size={14} marginRight=".3em" />} {children}</li>;
const Notices = ({ notices }) => notices.map((msg) => <ListItem key={msg} icon={InfoSignIcon} iconColor="info">{msg}</ListItem>);
@ -601,6 +607,7 @@ export async function openExportFinishedToast({ filePath, warnings, notices }) {
</UnorderedList>
);
// @ts-expect-error todo
await openDirToast({ filePath, html, width: 800, position: 'center', timer: hasWarnings ? undefined : 30000 });
}

View File

@ -14,7 +14,7 @@ export interface ParameterDialogParameter { value: string, label?: string, hint?
export type ParameterDialogParameters = Record<string, ParameterDialogParameter>;
const ParametersInput = ({ description, parameters: parametersIn, onChange, onSubmit, docUrl }: {
description?: string, parameters: ParameterDialogParameters, onChange: (a: ParameterDialogParameters) => void, onSubmit: () => void, docUrl?: string,
description?: string | undefined, parameters: ParameterDialogParameters, onChange: (a: ParameterDialogParameters) => void, onSubmit: () => void, docUrl?: string | undefined,
}) => {
const firstInputRef = useRef<HTMLInputElement>(null);
const [parameters, setParameters] = useState(parametersIn);
@ -67,6 +67,7 @@ export async function showParametersDialog({ title, description, parameters: par
};
const promise2 = (async () => {
// @ts-expect-error todo
const { isConfirmed } = await ReactSwal.fire({
title,
html: <ParametersInput description={description} parameters={parameters} onChange={(newParameters) => { parameters = newParameters; }} onSubmit={handleSubmit} docUrl={docUrl} />,

View File

@ -93,7 +93,7 @@ export async function loadLlcProject(path: string) {
};
}
export async function readEdlFile({ type, path, fps }: { type: EdlFileType, path: string, fps?: number }) {
export async function readEdlFile({ type, path, fps }: { type: EdlFileType, path: string, fps?: number | undefined }) {
if (type === 'csv') return loadCsvSeconds(path);
if (type === 'csv-frames') return loadCsvFrames(path, fps);
if (type === 'xmeml') return loadXmeml(path);
@ -110,7 +110,7 @@ export async function readEdlFile({ type, path, fps }: { type: EdlFileType, path
throw new Error('Invalid EDL type');
}
export async function askForEdlImport({ type, fps }: { type: EdlImportType, fps?: number }) {
export async function askForEdlImport({ type, fps }: { type: EdlImportType, fps?: number | undefined }) {
if (type === 'youtube') return askForYouTubeInput();
let filters;
@ -132,7 +132,7 @@ export async function askForEdlImport({ type, fps }: { type: EdlImportType, fps?
}
export async function exportEdlFile({ type, cutSegments, customOutDir, filePath, getFrameCount }: {
type: EdlExportType, cutSegments: Segment[], customOutDir?: string, filePath?: string, getFrameCount: (a: number) => number | undefined,
type: EdlExportType, cutSegments: Segment[], customOutDir?: string | undefined, filePath?: string | undefined, getFrameCount: (a: number) => number | undefined,
}) {
let filters;
let ext;

View File

@ -26,7 +26,7 @@ function getFrameFromVideo(video, format, quality) {
export default ({ formatTimecode, treatOutputFileModifiedTimeAsStart }) => {
const captureFramesRange = useCallback(async ({ customOutDir, filePath, fps, fromTime, toTime, estimatedMaxNumFiles, captureFormat, quality, filter, onProgress, outputTimestamps }: {
customOutDir, filePath: string, fps: number, fromTime: number, toTime: number, estimatedMaxNumFiles: number, captureFormat: string, quality: number, filter?: string, onProgress: (a: number) => void, outputTimestamps: boolean
customOutDir, filePath: string, fps: number, fromTime: number, toTime: number, estimatedMaxNumFiles: number, captureFormat: string, quality: number, filter?: string | undefined, onProgress: (a: number) => void, outputTimestamps: boolean
}) => {
const getSuffix = (prefix: string) => `${prefix}.${captureFormat}`;

View File

@ -17,6 +17,7 @@ export default function useNativeMenu(
const { x, y, onContext, onClose } = options;
const openMenu = useCallback((e: MouseEvent) => {
// @ts-expect-error todo
menu.popup({
window: remote.getCurrentWindow(),
x,

View File

@ -21,7 +21,7 @@ const { blackDetect, silenceDetect } = remote.require('./ffmpeg');
export default ({ filePath, workingRef, setWorking, setCutProgress, videoStream, duration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments, segmentsToChaptersOnly }: {
filePath?: string, workingRef: MutableRefObject<boolean>, setWorking: (w: { text: string, abortController?: AbortController } | undefined) => void, setCutProgress: (a: number | undefined) => void, videoStream, duration?: number, getRelevantTime: () => number, maxLabelLength: number, checkFileOpened: () => boolean, invertCutSegments: boolean, segmentsToChaptersOnly: boolean,
filePath?: string | undefined, workingRef: MutableRefObject<boolean>, setWorking: (w: { text: string, abortController?: AbortController } | undefined) => void, setCutProgress: (a: number | undefined) => void, videoStream, duration?: number | undefined, getRelevantTime: () => number, maxLabelLength: number, checkFileOpened: () => boolean, invertCutSegments: boolean, segmentsToChaptersOnly: boolean,
}) => {
// Segment related state
const segCounterRef = useRef(0);

View File

@ -19,7 +19,7 @@ export interface StateSegment extends SegmentBase {
}
export interface Segment extends SegmentBase {
name?: string,
name?: string | undefined,
}
export interface ApparentCutSegment extends ApparentSegmentBase {

View File

@ -44,16 +44,16 @@ function getFileBaseName(filePath?: string) {
return parsed.name;
}
export function getOutPath<T extends string | undefined>(a: { customOutDir?: string, filePath?: T, fileName: string }): T extends string ? string : undefined;
export function getOutPath({ customOutDir, filePath, fileName }: { customOutDir?: string, filePath?: string | undefined, fileName: string }) {
export function getOutPath<T extends string | undefined>(a: { customOutDir?: string | undefined, filePath?: T | undefined, fileName: string }): T extends string ? string : undefined;
export function getOutPath({ customOutDir, filePath, fileName }: { customOutDir?: string | undefined, filePath?: string | undefined, fileName: string }) {
if (filePath == null) return undefined;
return join(getOutDir(customOutDir, filePath), fileName);
}
export const getSuffixedFileName = (filePath: string | undefined, nameSuffix: string) => `${getFileBaseName(filePath)}-${nameSuffix}`;
export function getSuffixedOutPath<T extends string | undefined>(a: { customOutDir?: string, filePath?: T, nameSuffix: string }): T extends string ? string : undefined;
export function getSuffixedOutPath({ customOutDir, filePath, nameSuffix }: { customOutDir?: string, filePath?: string | undefined, nameSuffix: string }) {
export function getSuffixedOutPath<T extends string | undefined>(a: { customOutDir?: string | undefined, filePath?: T | undefined, nameSuffix: string }): T extends string ? string : undefined;
export function getSuffixedOutPath({ customOutDir, filePath, nameSuffix }: { customOutDir?: string | undefined, filePath?: string | undefined, nameSuffix: string }) {
if (filePath == null) return undefined;
return getOutPath({ customOutDir, filePath, fileName: getSuffixedFileName(filePath, nameSuffix) });
}
@ -107,10 +107,11 @@ export async function dirExists(dirPath) {
const testFailFsOperation = false;
// Retry because sometimes write operations fail on windows due to the file being locked for various reasons (often anti-virus) #272 #1797 #1704
export async function fsOperationWithRetry(operation, { signal, retries = 10, minTimeout = 100, maxTimeout = 2000, ...opts }: Options & { retries?: number, minTimeout?: number, maxTimeout?: number } = {}) {
export async function fsOperationWithRetry(operation, { signal, retries = 10, minTimeout = 100, maxTimeout = 2000, ...opts }: Options & { retries?: number | undefined, minTimeout?: number | undefined, maxTimeout?: number | undefined } = {}) {
return pRetry(async () => {
if (testFailFsOperation && Math.random() > 0.3) throw Object.assign(new Error('test delete failure'), { code: 'EPERM' });
await operation();
// @ts-expect-error todo
}, {
retries,
signal,
@ -391,7 +392,7 @@ function setDocumentExtraTitle(extra) {
document.title = extra != null ? `${baseTitle} - ${extra}` : baseTitle;
}
export function setDocumentTitle({ filePath, working, cutProgress }: { filePath?: string, working?: string, cutProgress?: number }) {
export function setDocumentTitle({ filePath, working, cutProgress }: { filePath?: string | undefined, working?: string | undefined, cutProgress?: number | undefined }) {
const parts: string[] = [];
if (filePath) parts.push(basename(filePath));
if (working) {

View File

@ -1,7 +1,7 @@
import padStart from 'lodash/padStart';
export function formatDuration({ seconds: totalSecondsIn, fileNameFriendly, showFraction = true, shorten = false, fps }: {
seconds?: number, fileNameFriendly?: boolean, showFraction?: boolean, shorten?: boolean, fps?: number,
seconds?: number | undefined, fileNameFriendly?: boolean | undefined, showFraction?: boolean | undefined, shorten?: boolean | undefined, fps?: number | undefined,
}) {
const totalSeconds = totalSecondsIn || 0;
const totalSecondsAbs = Math.abs(totalSeconds);

View File

@ -111,7 +111,7 @@ export const isMov = (format: string) => ['ismv', 'ipod', 'mp4', 'mov'].includes
type GetVideoArgsFn = (a: { streamIndex: number, outputIndex: number }) => string[] | undefined;
function getPerStreamFlags({ stream, outputIndex, outFormat, manuallyCopyDisposition = false, getVideoArgs = () => undefined }: {
stream, outputIndex: number, outFormat: string, manuallyCopyDisposition?: boolean, getVideoArgs?: GetVideoArgsFn
stream, outputIndex: number, outFormat: string, manuallyCopyDisposition?: boolean | undefined, getVideoArgs?: GetVideoArgsFn | undefined
}) {
let args: string[] = [];

View File

@ -5,7 +5,6 @@
"plugins": [{ "name": "typescript-plugin-css-modules" }],
"noEmit": true,
"exactOptionalPropertyTypes": false, // todo
"noImplicitAny": false, // todo
"checkJs": false, // todo
"allowJs": true, // todo