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:
parent
41c18546c2
commit
cb5a8c2c85
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
|
@ -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>();
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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'),
|
||||
|
@ -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 });
|
||||
}
|
||||
|
||||
|
@ -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} />,
|
||||
|
@ -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;
|
||||
|
@ -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}`;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -19,7 +19,7 @@ export interface StateSegment extends SegmentBase {
|
||||
}
|
||||
|
||||
export interface Segment extends SegmentBase {
|
||||
name?: string,
|
||||
name?: string | undefined,
|
||||
}
|
||||
|
||||
export interface ApparentCutSegment extends ApparentSegmentBase {
|
||||
|
13
src/util.ts
13
src/util.ts
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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[] = [];
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
"plugins": [{ "name": "typescript-plugin-css-modules" }],
|
||||
"noEmit": true,
|
||||
|
||||
"exactOptionalPropertyTypes": false, // todo
|
||||
"noImplicitAny": false, // todo
|
||||
"checkJs": false, // todo
|
||||
"allowJs": true, // todo
|
||||
|
Loading…
Reference in New Issue
Block a user