add types

pull/2119/head
Mikael Finstad 2 years ago
parent f6c1266588
commit fd27f2178e
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26

@ -1,3 +1,4 @@
// eslint-disable-line unicorn/filename-case
// eslint-disable-next-line import/no-extraneous-dependencies
import { test, expect, describe } from 'vitest';

@ -14,6 +14,7 @@ import CopyClipboardButton from '../components/CopyClipboardButton';
import Checkbox from '../components/Checkbox';
import { isWindows, showItemInFolder } from '../util';
import { ParseTimecode, SegmentBase } from '../types';
import { FindKeyframeMode } from '../ffmpeg';
const remote = window.require('@electron/remote');
const { dialog, shell } = remote;
@ -291,8 +292,8 @@ async function askForSegmentsRandomDurationRange() {
return parse(value);
}
async function askForSegmentsStartOrEnd(text) {
const { value } = await Swal.fire({
async function askForSegmentsStartOrEnd(text: string) {
const { value } = await Swal.fire<string>({
input: 'radio',
showCancelButton: true,
inputOptions: {
@ -323,7 +324,7 @@ export async function askForShiftSegments({ inputPlaceholder, parseTimecode }: {
return undefined;
}
const { value } = await Swal.fire({
const { value } = await Swal.fire<string>({
input: 'text',
showCancelButton: true,
inputValue: inputPlaceholder,
@ -352,14 +353,14 @@ export async function askForAlignSegments() {
const startOrEnd = await askForSegmentsStartOrEnd(i18n.t('Do you want to align the segment start or end timestamps to keyframes?'));
if (startOrEnd == null) return undefined;
const { value: mode } = await Swal.fire({
const { value: mode } = await Swal.fire<FindKeyframeMode>({
input: 'radio',
showCancelButton: true,
inputOptions: {
nearest: i18n.t('Nearest keyframe'),
before: i18n.t('Previous keyframe'),
after: i18n.t('Next keyframe'),
},
} satisfies Record<FindKeyframeMode, unknown>,
inputValue: 'before',
text: i18n.t('Do you want to align segment times to the nearest, previous or next keyframe?'),
});

@ -13,15 +13,28 @@ import { createNumSegments as createNumSegmentsDialog, createFixedDurationSegmen
import { createSegment, findSegmentsAtCursor, sortSegments, invertSegments, combineOverlappingSegments as combineOverlappingSegments2, combineSelectedSegments as combineSelectedSegments2, isDurationValid, getSegApparentStart, getSegApparentEnd as getSegApparentEnd2, addSegmentColorIndex } from '../segments';
import * as ffmpegParameters from '../ffmpeg-parameters';
import { maxSegmentsAllowed } from '../util/constants';
import { ParseTimecode, SegmentBase, SegmentToExport, StateSegment, UpdateSegAtIndex } from '../types';
import { ApparentCutSegment, ParseTimecode, SegmentBase, SegmentToExport, StateSegment, UpdateSegAtIndex } from '../types';
import safeishEval from '../worker/eval';
import { ScopeSegment } from '../../../../types';
import { FFprobeStream } from '../../../../ffprobe';
const { ffmpeg: { blackDetect, silenceDetect } } = window.require('@electron/remote').require('./index.js');
function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoStream, duration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments, segmentsToChaptersOnly, timecodePlaceholder, parseTimecode }: {
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, timecodePlaceholder: string, parseTimecode: ParseTimecode,
filePath?: string | undefined,
workingRef: MutableRefObject<boolean>,
setWorking: (w: { text: string, abortController?: AbortController } | undefined) => void,
setCutProgress: (a: number | undefined) => void,
videoStream: FFprobeStream | undefined,
duration?: number | undefined,
getRelevantTime: () => number,
maxLabelLength: number,
checkFileOpened: () => boolean,
invertCutSegments: boolean,
segmentsToChaptersOnly: boolean,
timecodePlaceholder: string,
parseTimecode: ParseTimecode,
}) {
// Segment related state
const segCounterRef = useRef(0);
@ -165,7 +178,7 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt
loadCutSegments(newSegments, true);
}, [currentApparentCutSeg.end, currentApparentCutSeg.start, filePath, loadCutSegments, videoStream]);
const removeSegments = useCallback((removeSegmentIds) => {
const removeSegments = useCallback((removeSegmentIds: string[]) => {
setCutSegments((existingSegments) => {
if (existingSegments.length === 1 && existingSegments[0]!.start == null && existingSegments[0]!.end == null) {
return existingSegments; // We are at initial segment, nothing more we can do (it cannot be removed)
@ -181,7 +194,7 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt
});
}, [clearSegCounter, createInitialCutSegments, setCutSegments]);
const removeCutSegment = useCallback((index) => {
const removeCutSegment = useCallback((index: number) => {
removeSegments([cutSegments[index]!.segId]);
}, [cutSegments, removeSegments]);
@ -247,9 +260,9 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt
updateSegAtIndex(currentSegIndexSafe, { [type]: Math.min(Math.max(time, 0), duration) });
}, [currentSegIndexSafe, getSegApparentEnd, currentCutSeg, duration, updateSegAtIndex]);
const modifySelectedSegmentTimes = useCallback(async (transformSegment, concurrency = 5) => {
const modifySelectedSegmentTimes = useCallback(async (transformSegment: <T extends ApparentCutSegment>(s: T) => Promise<T> | T, concurrency = 5) => {
if (duration == null) throw new Error();
const clampValue = (val) => Math.min(Math.max(val, 0), duration);
const clampValue = (val: number) => Math.min(Math.max(val, 0), duration);
let newSegments = await pMap(apparentCutSegments, async (segment) => {
if (!isSegmentSelected(segment)) return segment; // pass thru non-selected segments
@ -287,13 +300,13 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt
await modifySelectedSegmentTimes(async (segment) => {
const newSegment = { ...segment };
async function align(key) {
const align = async (key: 'start' | 'end') => {
const time = newSegment[key];
if (filePath == null) throw new Error();
const keyframe = await findKeyframeNearTime({ filePath, streamIndex: videoStream.index, time, mode });
if (keyframe == null) throw new Error(`Cannot find any keyframe within 60 seconds of frame ${time}`);
newSegment[key] = keyframe;
}
};
if (startOrEnd.includes('start')) await align('start');
if (startOrEnd.includes('end')) await align('end');
return newSegment;
@ -305,7 +318,7 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt
}
}, [filePath, videoStream, modifySelectedSegmentTimes, setWorking, workingRef]);
const updateSegOrder = useCallback((index, newOrder) => {
const updateSegOrder = useCallback((index: number, newOrder: number) => {
if (newOrder > cutSegments.length - 1 || newOrder < 0) return;
const newSegments = [...cutSegments];
const removedSeg = newSegments.splice(index, 1)[0];
@ -315,7 +328,7 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt
setCurrentSegIndex(newOrder);
}, [cutSegments, setCurrentSegIndex, setCutSegments]);
const updateSegOrders = useCallback((newOrders) => {
const updateSegOrders = useCallback((newOrders: string[]) => {
const newSegments = sortBy(cutSegments, (seg) => newOrders.indexOf(seg.segId));
const newCurrentSegIndex = newOrders.indexOf(currentCutSeg.segId);
setCutSegments(newSegments);
@ -351,7 +364,7 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt
}
}, [currentCutSeg.start, currentCutSeg.end, getRelevantTime, duration, cutSegments, createIndexedSegment, setCutSegments, setCurrentSegIndex]);
const duplicateSegment = useCallback((segment) => {
const duplicateSegment = useCallback((segment: Pick<StateSegment, 'start' | 'end'> & Partial<Pick<StateSegment, 'name'>>) => {
try {
// Cannot duplicate if seg is not finished
if (segment.start === undefined && segment.end === undefined) return;
@ -411,7 +424,7 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt
}
}, [checkFileOpened, getRelevantTime, setCutTime]);
const onLabelSegment = useCallback(async (index) => {
const onLabelSegment = useCallback(async (index: number) => {
const { name } = cutSegments[index]!;
const value = await labelSegmentDialog({ currentName: name, maxLength: maxLabelLength });
if (value != null) updateSegAtIndex(index, { name: value });
@ -438,7 +451,7 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt
const segment = cutSegments[firstSegmentAtCursorIndex];
if (segment == null) throw new Error();
const getNewName = (oldName, suffix) => oldName && `${segment.name} ${suffix}`;
const getNewName = (oldName: string, suffix: string) => oldName && `${segment.name} ${suffix}`;
const firstPart = createIndexedSegment({ segment: { name: getNewName(segment.name, '1'), start: segment.start, end: relevantTime }, incrementCount: false });
const secondPart = createIndexedSegment({ segment: { name: getNewName(segment.name, '2'), start: relevantTime, end: segment.end }, incrementCount: true });
@ -544,8 +557,8 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt
const removeSelectedSegments = useCallback(() => removeSegments(selectedSegmentsRaw.map((seg) => seg.segId)), [removeSegments, selectedSegmentsRaw]);
const selectOnlySegment = useCallback((seg) => setDeselectedSegmentIds(Object.fromEntries(cutSegments.filter((s) => s.segId !== seg.segId).map((s) => [s.segId, true]))), [cutSegments]);
const toggleSegmentSelected = useCallback((seg) => setDeselectedSegmentIds((existing) => ({ ...existing, [seg.segId]: !existing[seg.segId] })), []);
const selectOnlySegment = useCallback((seg: Pick<StateSegment, 'segId'>) => setDeselectedSegmentIds(Object.fromEntries(cutSegments.filter((s) => s.segId !== seg.segId).map((s) => [s.segId, true]))), [cutSegments]);
const toggleSegmentSelected = useCallback((seg: Pick<StateSegment, 'segId'>) => setDeselectedSegmentIds((existing) => ({ ...existing, [seg.segId]: !existing[seg.segId] })), []);
const deselectAllSegments = useCallback(() => setDeselectedSegmentIds(Object.fromEntries(cutSegments.map((s) => [s.segId, true]))), [cutSegments]);
const invertSelectedSegments = useCallback(() => setDeselectedSegmentIds((existing) => Object.fromEntries(cutSegments.map((s) => [s.segId, !existing[s.segId]]))), [cutSegments]);
const selectAllSegments = useCallback(() => setDeselectedSegmentIds({}), []);

Loading…
Cancel
Save