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:
parent
52f615421f
commit
7463049ee5
@ -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 && (
|
||||
|
@ -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'}"`}
|
||||
"ffmpeg" <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>
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user