Merge branch 'master1'

3.68.0.1
nieve 4 months ago
commit 31bb9357fe

5
.github/pull.yml vendored

@ -0,0 +1,5 @@
version: "1"
rules:
- base: master
upstream: mifi:master # change `wei` to the owner of upstream repo
mergeMethod: merge

@ -4,8 +4,8 @@ on:
push:
tags:
- 'v*'
schedule:
- cron: '0 10 * * *'
# schedule:
# - cron: '0 10 * * *'
workflow_dispatch:
inputs:
tmate_enabled:
@ -25,8 +25,7 @@ jobs:
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest, windows-11-arm]
# os: [windows-latest]
os: [ ubuntu-latest, windows-latest]
steps:
- name: Setup tmate session

@ -1,3 +1,7 @@
Releases: https://github.com/ac615223s5/lossless-cut/releases
Forked from https://github.com/mifi/lossless-cut/
<div align="center">
<br>
<p><a href="https://mifi.no/losslesscut/"><img src="src/renderer/src/icon.svg" width="120" alt="LosslessCut" /></a></p>

@ -334,16 +334,16 @@ 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 getSwal().Swal.fire<FindKeyframeMode | 'opposing'>({
const { value: mode } = await getSwal().Swal.fire<FindKeyframeMode>({
input: 'radio',
showCancelButton: true,
inputOptions: {
nearest: i18n.t('Nearest keyframe'),
before: i18n.t('Previous keyframe'),
after: i18n.t('Next keyframe'),
opposing: i18n.t('Segment start to previous keyframe and end to next keyframe'),
} satisfies Record<FindKeyframeMode | 'opposing', unknown>,
inputValue: 'before',
keyframeCutFix: i18n.t('True keyframe cut'),
} satisfies Record<FindKeyframeMode, unknown>,
inputValue: 'keyframeCutFix',
text: i18n.t('Do you want to align segment times to the nearest, previous or next keyframe?'),
});

@ -108,7 +108,7 @@ export const findNextKeyframe = (keyframes: Frame[], time: number) => keyframes.
const findPreviousKeyframe = (keyframes: Frame[], time: number) => keyframes.findLast((keyframe) => keyframe.time <= time);
const findNearestKeyframe = (keyframes: Frame[], time: number) => minBy(keyframes, (keyframe) => Math.abs(keyframe.time - time));
export type FindKeyframeMode = 'nearest' | 'before' | 'after';
export type FindKeyframeMode = 'nearest' | 'before' | 'after' | 'keyframeCutFix';
function findKeyframe(keyframes: Frame[], time: number, mode: FindKeyframeMode) {
switch (mode) {
@ -121,6 +121,9 @@ function findKeyframe(keyframes: Frame[], time: number, mode: FindKeyframeMode)
case 'after': {
return findNextKeyframe(keyframes, time);
}
case 'keyframeCutFix': {
return findNextKeyframe(keyframes,time);
}
default: {
return undefined;
}

@ -8,8 +8,7 @@ import sortBy from 'lodash/sortBy';
import { Trans, useTranslation } from 'react-i18next';
import { FaLink } from 'react-icons/fa';
import TextInput from '../components/TextInput';
import { detectSceneChanges as ffmpegDetectSceneChanges, readFrames, mapTimesToSegments, findKeyframeNearTime } from '../ffmpeg';
import { detectSceneChanges as ffmpegDetectSceneChanges, readFrames, mapTimesToSegments, findKeyframeNearTime, getStreamFps } from '../ffmpeg';
import { getFileSize, shuffleArray } from '../util';
import { errorToast } from '../swal';
import { createNumSegments as createNumSegmentsDialog, createFixedByteSixedSegments as createFixedByteSixedSegmentsDialog, createRandomSegments as createRandomSegmentsDialog, labelSegmentDialog, askForShiftSegments, askForAlignSegments, selectSegmentsByLabelDialog, askForSegmentDuration, toastError } from '../dialogs';
@ -516,25 +515,50 @@ function useSegments({ filePath, workingRef, setWorking, setProgress, videoStrea
if (response == null) return;
setWorking({ text: i18n.t('Aligning segments to keyframes') });
const { mode, startOrEnd } = response;
if (filePath == null) throw new Error();
const frameTime = 1 / (getStreamFps(videoStream) || 1000);
await modifySelectedSegmentTimes(async (segment) => {
const newSegment = { ...segment };
const align = async (key: 'start' | 'end') => {
async function align(key: string) {
const time = newSegment[key];
invariant(filePath != null);
if (time != null) {
const keyframe = await findKeyframeNearTime({
filePath,
streamIndex: videoStream.index,
time,
mode: mode === 'opposing' ? (key === 'start' ? 'before' : 'after') : mode,
});
if (keyframe == null) throw new UserFacingError(i18n.t('Cannot find any keyframe within 60 seconds of frame {{time}}', { time }));
let keyframe = await findKeyframeNearTime({ filePath, streamIndex: videoStream.index, time, mode });
if (keyframe === undefined) {
if (mode !== 'keyframeCutFix') {
throw new UserFacingError(i18n.t('Cannot find any keyframe within 60 seconds of frame {{time}}', { time }));
}
keyframe = fileDuration;
console.log(2,time,keyframe);
}
newSegment[key] = keyframe;
}
};
if (startOrEnd.includes('start')) await align('start');
if (startOrEnd.includes('end')) await align('end');
}
if (startOrEnd.includes('start')) {
if (mode === 'keyframeCutFix') {
newSegment.start += frameTime * 0.3;
}
await align('start');
if (mode === 'keyframeCutFix') {
newSegment.start -= frameTime * 0.7;
}
}
if (startOrEnd.includes('end')) {
await align('end');
if (mode === 'keyframeCutFix' && newSegment.end !== fileDuration) {
newSegment.end -= frameTime * 0.3;
}
}
if (startOrEnd.includes('start')) {
newSegment.start = Math.min(newSegment.start, newSegment.end - frameTime * 0.99); // don't know how ffmpeg interprets cuts between frames
} else {
newSegment.end = Math.max(newSegment.start + frameTime * 0.99, newSegment.end);
}
return newSegment;
});
} catch (err) {
@ -542,7 +566,7 @@ function useSegments({ filePath, workingRef, setWorking, setProgress, videoStrea
} finally {
setWorking(undefined);
}
}, [videoStream, workingRef, setWorking, modifySelectedSegmentTimes, filePath, handleError]);
}, [filePath, videoStream, modifySelectedSegmentTimes, setWorking, workingRef, fileDuration, handleError]);
const updateSegOrder = useCallback((index: number, newOrder: number) => {
if (newOrder > cutSegments.length - 1 || newOrder < 0) return;

Loading…
Cancel
Save