1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-21 18:02:35 +01:00

improve settings

This commit is contained in:
Mikael Finstad 2024-08-07 16:20:27 +02:00
parent 52f615421f
commit 7463049ee5
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26
3 changed files with 137 additions and 104 deletions

View File

@ -2847,7 +2847,7 @@ function App() {
/>
</div>
<ExportConfirm areWeCutting={areWeCutting} nonFilteredSegmentsOrInverse={nonFilteredSegmentsOrInverse} selectedSegments={selectedSegmentsOrInverse} segmentsToExport={segmentsToExport} willMerge={willMerge} visible={exportConfirmVisible} onClosePress={closeExportConfirm} onExportConfirm={onExportConfirm} renderOutFmt={renderOutFmt} outputDir={outputDir} numStreamsTotal={numStreamsTotal} numStreamsToCopy={numStreamsToCopy} onShowStreamsSelectorClick={handleShowStreamsSelectorClick} outFormat={fileFormat} setOutSegTemplate={setOutSegTemplate} outSegTemplate={outSegTemplateOrDefault} generateOutSegFileNames={generateOutSegFileNames} currentSegIndexSafe={currentSegIndexSafe} mainCopiedThumbnailStreams={mainCopiedThumbnailStreams} needSmartCut={needSmartCut} mergedOutFileName={mergedOutFileName} setMergedOutFileName={setMergedOutFileName} smartCutBitrate={smartCutBitrate} setSmartCutBitrate={setSmartCutBitrate} />
<ExportConfirm areWeCutting={areWeCutting} nonFilteredSegmentsOrInverse={nonFilteredSegmentsOrInverse} selectedSegments={selectedSegmentsOrInverse} segmentsToExport={segmentsToExport} willMerge={willMerge} visible={exportConfirmVisible} onClosePress={closeExportConfirm} onExportConfirm={onExportConfirm} renderOutFmt={renderOutFmt} outputDir={outputDir} numStreamsTotal={numStreamsTotal} numStreamsToCopy={numStreamsToCopy} onShowStreamsSelectorClick={handleShowStreamsSelectorClick} outFormat={fileFormat} setOutSegTemplate={setOutSegTemplate} outSegTemplate={outSegTemplateOrDefault} generateOutSegFileNames={generateOutSegFileNames} currentSegIndexSafe={currentSegIndexSafe} mainCopiedThumbnailStreams={mainCopiedThumbnailStreams} needSmartCut={needSmartCut} mergedOutFileName={mergedOutFileName} setMergedOutFileName={setMergedOutFileName} smartCutBitrate={smartCutBitrate} setSmartCutBitrate={setSmartCutBitrate} toggleSettings={toggleSettings} />
<Sheet visible={streamsSelectorShown} onClosePress={() => setStreamsSelectorShown(false)} maxWidth={1000}>
{mainStreams && filePath != null && (

View File

@ -4,7 +4,7 @@ import { WarningSignIcon, CrossIcon } from 'evergreen-ui';
import { FaRegCheckCircle } from 'react-icons/fa';
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next';
import { IoIosHelpCircle } from 'react-icons/io';
import { IoIosHelpCircle, IoIosSettings } from 'react-icons/io';
import type { SweetAlertIcon } from 'sweetalert2';
import ExportButton from './ExportButton';
@ -64,6 +64,7 @@ function ExportConfirm({
setMergedOutFileName,
smartCutBitrate,
setSmartCutBitrate,
toggleSettings,
} : {
areWeCutting: boolean,
selectedSegments: InverseCutSegment[],
@ -89,6 +90,7 @@ function ExportConfirm({
setMergedOutFileName: (a: string) => void,
smartCutBitrate: number | undefined,
setSmartCutBitrate: Dispatch<SetStateAction<number | undefined>>,
toggleSettings: () => void,
}) {
const { t } = useTranslation();
@ -151,6 +153,7 @@ function ExportConfirm({
const onAvoidNegativeTsHelpPress = useCallback(() => {
// https://ffmpeg.org/ffmpeg-all.html#Format-Options
// https://github.com/mifi/lossless-cut/issues/1206
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.'),
make_zero: i18n.t('Shift timestamps so that the first timestamp is 0. (LosslessCut default)'),
@ -309,6 +312,61 @@ function ExportConfirm({
<table className={styles['options']}>
<tbody>
{areWeCutting && (
<tr>
<td>
{t('Shift all start times')}
</td>
<td>
<Select value={cutFromAdjustmentFrames} onChange={(e) => setCutFromAdjustmentFrames(Number(e.target.value))} style={{ height: 20, marginLeft: 5 }}>
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((v) => <option key={v} value={v}>{t('+{{numFrames}} frames', { numFrames: v, count: v })}</option>)}
</Select>
</td>
<td>
<HelpIcon onClick={onCutFromAdjustmentFramesHelpPress} />
</td>
</tr>
)}
{isMov && (
<>
<tr>
<td>
{t('Enable MOV Faststart?')}
</td>
<td>
<MovFastStartButton />
{isIpod && !movFastStart && <div style={warningStyle}>{t('For the ipod format, it is recommended to activate this option')}</div>}
</td>
<td>
{isIpod && !movFastStart ? (
<WarningSignIcon verticalAlign="middle" color="warning" />
) : (
<HelpIcon onClick={onMovFastStartHelpPress} />
)}
</td>
</tr>
<tr>
<td>
{t('Preserve all MP4/MOV metadata?')}
{isIpod && preserveMovData && <div style={warningStyle}>{t('For the ipod format, it is recommended to deactivate this option')}</div>}
</td>
<td>
<PreserveMovDataButton />
</td>
<td>
{isIpod && preserveMovData ? (
<WarningSignIcon verticalAlign="middle" color="warning" />
) : (
<HelpIcon onClick={onPreserveMovDataHelpPress} />
)}
</td>
</tr>
</>
)}
{willMerge && (
<>
<tr>
@ -403,60 +461,6 @@ function ExportConfirm({
</>
)}
{areWeCutting && (
<tr>
<td>
{t('Shift all start times')}
</td>
<td>
<Select value={cutFromAdjustmentFrames} onChange={(e) => setCutFromAdjustmentFrames(Number(e.target.value))} style={{ height: 20, marginLeft: 5 }}>
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((v) => <option key={v} value={v}>{t('+{{numFrames}} frames', { numFrames: v, count: v })}</option>)}
</Select>
</td>
<td>
<HelpIcon onClick={onCutFromAdjustmentFramesHelpPress} />
</td>
</tr>
)}
{isMov && (
<>
<tr>
<td>
{t('Enable MOV Faststart?')}
</td>
<td>
<MovFastStartButton />
{isIpod && !movFastStart && <div style={warningStyle}>{t('For the ipod format, it is recommended to activate this option')}</div>}
</td>
<td>
{isIpod && !movFastStart ? (
<WarningSignIcon verticalAlign="middle" color="warning" />
) : (
<HelpIcon onClick={onMovFastStartHelpPress} />
)}
</td>
</tr>
<tr>
<td>
{t('Preserve all MP4/MOV metadata?')}
{isIpod && preserveMovData && <div style={warningStyle}>{t('For the ipod format, it is recommended to deactivate this option')}</div>}
</td>
<td>
<PreserveMovDataButton />
</td>
<td>
{isIpod && preserveMovData ? (
<WarningSignIcon verticalAlign="middle" color="warning" />
) : (
<HelpIcon onClick={onPreserveMovDataHelpPress} />
)}
</td>
</tr>
</>
)}
{!needSmartCut && (() => {
const avoidNegativeTsWarn = (() => {
if (willMerge) {
@ -474,7 +478,7 @@ function ExportConfirm({
return (
<tr>
<td>
{`"${'avoid_negative_ts'}"`}
&quot;ffmpeg&quot; <code className="highlighted">avoid_negative_ts</code>
{avoidNegativeTsWarn != null && <div style={warningStyle}>{avoidNegativeTsWarn}</div>}
</td>
<td>
@ -507,6 +511,16 @@ function ExportConfirm({
<HelpIcon onClick={onFfmpegExperimentalHelpPress} />
</td>
</tr>
<tr>
<td>
{t('More settings')}
</td>
<td>
<IoIosSettings size={24} role="button" onClick={toggleSettings} style={{ marginLeft: 5 }} />
</td>
<td />
</tr>
</tbody>
</table>
</div>

View File

@ -103,13 +103,6 @@ function Settings({
</thead>
<tbody>
<Row>
<KeyCell>{t('Show advanced settings')}</KeyCell>
<td>
<Switch checked={showAdvanced} onCheckedChange={setShowAdvanced} />
</td>
</Row>
<Row>
<KeyCell><GlobeIcon style={{ verticalAlign: 'middle', marginRight: '.5em' }} /> App language</KeyCell>
<td>
@ -120,6 +113,30 @@ function Settings({
</td>
</Row>
<Row>
<KeyCell>
{t('Show advanced settings')}
<div style={detailsStyle}>
{!showAdvanced && t('Advanced settings are currently not visible.')}
</div>
</KeyCell>
<td>
<Switch checked={showAdvanced} onCheckedChange={setShowAdvanced} />
</td>
</Row>
<Row>
<KeyCell>
{t('Show export options screen before exporting?')}
<div style={detailsStyle}>
{t('This gives you an overview of the export and allows you to customise more parameters before exporting.')}
</div>
</KeyCell>
<td>
<Switch checked={exportConfirmEnabled} onCheckedChange={toggleExportConfirmEnabled} />
</td>
</Row>
{showAdvanced && (
<Row>
<KeyCell>
@ -184,12 +201,15 @@ function Settings({
<KeyCell>
{t('Choose cutting mode: Remove or keep selected segments from video when exporting?')}<br />
<div style={detailsStyle}>
<b>{t('Keep')}</b>: {t('The video inside segments will be kept, while the video outside will be discarded.')}<br />
<b>{t('Remove')}</b>: {t('The video inside segments will be discarded, while the video surrounding them will be kept.')}
{invertCutSegments ? (
<><b>{t('Remove')}</b>: {t('The video inside segments will be discarded, while the video surrounding them will be kept.')}</>
) : (
<><b>{t('Keep')}</b>: {t('The video inside segments will be kept, while the video outside will be discarded.')}</>
)}
</div>
</KeyCell>
<td>
<Button iconBefore={FaYinYang} appearance={invertCutSegments ? 'default' : 'primary'} intent="success" onClick={() => setInvertCutSegments((v) => !v)}>
<Button iconBefore={FaYinYang} appearance="primary" intent={invertCutSegments ? 'danger' : 'success'} onClick={() => setInvertCutSegments((v) => !v)}>
{invertCutSegments ? t('Remove') : t('Keep')}
</Button>
</td>
@ -203,10 +223,10 @@ function Settings({
</div>
</KeyCell>
<td>
<div>{customOutDir}</div>
<Button iconBefore={customOutDir ? FolderCloseIcon : DocumentIcon} onClick={changeOutDir}>
{customOutDir ? t('Custom working directory') : t('Same directory as input file')}...
</Button>
<div>{customOutDir}</div>
{customOutDir && (
<Button
height={20}
@ -250,13 +270,13 @@ function Settings({
<div style={detailsStyle}>
{keyframeCut ? (
<>
{t('Cut at the nearest keyframe (not accurate time.) Equiv to')}:<br />
<code className="highlighted">ffmpeg -ss -i ...</code>
<b>{t('Keyframe cut')}</b>: {t('Cut at the nearest keyframe (not accurate time.) Equiv to')}:<br />
<code className="highlighted">ffmpeg -ss -i input.mp4</code>
</>
) : (
<>
{t('Accurate time but could leave an empty portion at the beginning of the video. Equiv to')}:<br />
<code className="highlighted">ffmpeg -i -ss ...</code>
<b>{t('Normal cut')}</b>: {t('Accurate time but could leave an empty portion at the beginning of the video. Equiv to')}:<br />
<code className="highlighted">ffmpeg -i -ss input.mp4</code>
</>
)}
</div>
@ -299,17 +319,19 @@ function Settings({
</td>
</Row>
<Row>
<KeyCell>
{t('Snapshot capture method')}
<div style={detailsStyle}>{t('FFmpeg capture method might sometimes capture more correct colors, but the captured snapshot might be off by one or more frames, relative to the preview.')}</div>
</KeyCell>
<td>
<Button onClick={() => setCaptureFrameMethod((existing) => (existing === 'ffmpeg' ? 'videotag' : 'ffmpeg'))}>
{captureFrameMethod === 'ffmpeg' ? t('FFmpeg') : t('HTML video tag')}
</Button>
</td>
</Row>
{showAdvanced && (
<Row>
<KeyCell>
{t('Snapshot capture method')}
<div style={detailsStyle}>{t('FFmpeg capture method might sometimes capture more correct colors, but the captured snapshot might be off by one or more frames, relative to the preview.')}</div>
</KeyCell>
<td>
<Button onClick={() => setCaptureFrameMethod((existing) => (existing === 'ffmpeg' ? 'videotag' : 'ffmpeg'))}>
{captureFrameMethod === 'ffmpeg' ? t('FFmpeg') : t('HTML video tag')}
</Button>
</td>
</Row>
)}
<Row>
<KeyCell>{t('Snapshot capture quality')}</KeyCell>
@ -319,14 +341,16 @@ function Settings({
</td>
</Row>
<Row>
<KeyCell>{t('File names of extracted video frames')}</KeyCell>
<td>
<Button iconBefore={captureFrameFileNameFormat === 'timestamp' ? TimeIcon : NumericalIcon} onClick={() => setCaptureFrameFileNameFormat((existing) => (existing === 'timestamp' ? 'index' : 'timestamp'))}>
{captureFrameFileNameFormat === 'timestamp' ? t('Frame timestamp') : t('Frame number')}
</Button>
</td>
</Row>
{showAdvanced && (
<Row>
<KeyCell>{t('File names of extracted video frames')}</KeyCell>
<td>
<Button iconBefore={captureFrameFileNameFormat === 'timestamp' ? TimeIcon : NumericalIcon} onClick={() => setCaptureFrameFileNameFormat((existing) => (existing === 'timestamp' ? 'index' : 'timestamp'))}>
{captureFrameFileNameFormat === 'timestamp' ? t('Frame timestamp') : t('Frame number')}
</Button>
</td>
</Row>
)}
<Header title={t('Keyboard, mouse and input')} />
@ -391,6 +415,7 @@ function Settings({
</td>
</Row>
<Header title={t('User interface')} />
{showAdvanced && (
@ -421,6 +446,13 @@ function Settings({
</Row>
)}
<Row>
<KeyCell>{t('Prefer strong colors')}</KeyCell>
<td>
<Switch checked={preferStrongColors} onCheckedChange={setPreferStrongColors} />
</td>
</Row>
<Row>
<KeyCell>{t('In timecode show')}</KeyCell>
<td>
@ -430,22 +462,9 @@ function Settings({
</td>
</Row>
<Row>
<KeyCell>{t('Prefer strong colors')}</KeyCell>
<td>
<Switch checked={preferStrongColors} onCheckedChange={setPreferStrongColors} />
</td>
</Row>
<Header title={t('Prompts and dialogs')} />
<Row>
<KeyCell>{t('Show export options screen before exporting?')}</KeyCell>
<td>
<Switch checked={exportConfirmEnabled} onCheckedChange={toggleExportConfirmEnabled} />
</td>
</Row>
<Row>
<KeyCell>{t('Show notifications')}</KeyCell>
<td>