change to EPOCH_MS

and more fixes/improveement
pull/1548/head
Mikael Finstad 2023-04-07 16:48:32 +09:00
rodzic 8dcd6113d5
commit 7e056410ec
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 25AB36E3E81CBC26
3 zmienionych plików z 19 dodań i 21 usunięć

Wyświetl plik

@ -9,6 +9,7 @@ When exporting multiple segments as separate files, LosslessCut offers you the a
| `${FILENAME}` | The original filename without the extension (e.g. `Beach Trip` for a file named `Beach Trip.mp4`)
| `${EXT}` | The extension of the file (e.g.: `.mp4`, `.mkv`)
| `${SEG_NUM}` | Number of the segment (e.g. `1`, `2` or `3`)
| `${EPOCH_MS}` | Number of milliseconds since epoch (e.g. `1680852771465`)
| `${SEG_LABEL}` | The label of the segment (e.g. `Getting_Lunch`)
| `${SEG_SUFFIX}` | If a label exists for this segment, the label will be used, prepended by `-`. Otherwise, the segment number prepended by `-seg` will be used (e.g. `-Getting_Lunch`, `-seg1`)
| `${CUT_FROM}` | The timestamp for the beginning of the segment in `hh.mm.ss.sss` format (e.g. `00.00.27.184`)

Wyświetl plik

@ -4,6 +4,7 @@ import i18n from 'i18next';
import { useTranslation } from 'react-i18next';
import { WarningSignIcon, ErrorIcon, Button, IconButton, TickIcon, ResetIcon } from 'evergreen-ui';
import withReactContent from 'sweetalert2-react-content';
import { IoIosHelpCircle } from 'react-icons/io';
import Swal from '../swal';
import HighlightedText from './HighlightedText';
@ -12,6 +13,8 @@ import useUserSettings from '../hooks/useUserSettings';
const ReactSwal = withReactContent(Swal);
const electron = window.require('electron');
// eslint-disable-next-line no-template-curly-in-string
const extVar = '${EXT}';
@ -26,7 +29,7 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate
const [error, setError] = useState();
const [outSegFileNames, setOutSegFileNames] = useState();
const [shown, setShown] = useState();
const inputRef = useRef(null);
const inputRef = useRef();
const { t } = useTranslation();
@ -84,18 +87,14 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate
const needToShow = shown || error != null;
const onTextClick = useCallback(() => {
inputRef.current.focus();
}, []);
const onVariableClick = useCallback((variable) => {
const input = inputRef.current;
const startPos = input.selectionStart;
const endPos = input.selectionEnd;
const newValue = `${text.slice(0, startPos)}${'${' + variable + '}' + text.slice(endPos)}`;
const newValue = `${text.slice(0, startPos)}${`\${${variable}}${text.slice(endPos)}`}`;
setText(newValue);
// Move the cursor to after the inserted variable
const newPos = startPos + variable.length + 2;
input.selectionStart = newPos;
@ -113,7 +112,7 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate
{needToShow && (
<>
<div style={{ display: 'flex', alignItems: 'center', marginBottom: 5, marginTop: 10 }}>
<input type="text" ref={inputRef} style={inputStyle} onChange={onTextChange} onClick={onTextClick} value={text} autoComplete="off" autoCapitalize="off" autoCorrect="off" />
<input type="text" ref={inputRef} style={inputStyle} onChange={onTextChange} value={text} autoComplete="off" autoCapitalize="off" autoCorrect="off" />
{outSegFileNames != null && <Button height={20} onClick={onAllSegmentsPreviewPress} marginLeft={5}>{t('Preview')}</Button>}
<Button title={t('Whether or not to sanitize output file names (sanitizing removes special characters)')} marginLeft={5} height={20} onClick={toggleSafeOutputFileName} intent={safeOutputFileName ? 'success' : 'danger'}>{safeOutputFileName ? t('Sanitize') : t('No sanitize')}</Button>
@ -123,9 +122,10 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate
<div style={{ maxWidth: 600 }}>
{error != null && <div style={{ marginBottom: '1em' }}><ErrorIcon color="var(--red9)" /> {i18n.t('There is an error in the file name template:')} {error}</div>}
{isMissingExtension && <div style={{ marginBottom: '1em' }}><WarningSignIcon color="var(--amber9)" /> {i18n.t('The file name template is missing {{ext}} and will result in a file without the suggested extension. This may result in an unplayable output file.', { ext: extVar })}</div>}
<div style={{ fontSize: '.8em', color: 'var(--gray11)' }}>
{`${i18n.t('Variables')}`}{': '}
{['FILENAME', 'TIMESTAMP', 'CUT_FROM', 'CUT_TO', 'SEG_NUM', 'SEG_LABEL', 'SEG_SUFFIX', 'EXT', 'SEG_TAGS.XX'].map((variable) => (
<div style={{ fontSize: '.8em', color: 'var(--gray11)', display: 'flex', gap: '.3em', flexWrap: 'wrap', alignItems: 'center' }}>
{`${i18n.t('Variables')}:`}
<IoIosHelpCircle fontSize="1.3em" color="var(--gray12)" role="button" cursor="pointer" onClick={() => electron.shell.openExternal('https://github.com/mifi/lossless-cut/blob/master/import-export.md#customising-exported-file-names')} />
{['FILENAME', 'CUT_FROM', 'CUT_TO', 'SEG_NUM', 'SEG_LABEL', 'SEG_SUFFIX', 'EXT', 'SEG_TAGS.XX', 'EPOCH_MS'].map((variable) => (
<span key={variable} role="button" style={{ cursor: 'pointer', marginRight: '.2em' }} onClick={() => onVariableClick(variable)}>{variable}</span>
))}
</div>

Wyświetl plik

@ -65,15 +65,9 @@ export function getOutSegError({ fileNames, filePath, outputDir, safeOutputFileN
// This is used as a fallback and so it has to always generate unique file names
// eslint-disable-next-line no-template-curly-in-string
export const defaultOutSegTemplate = '${FILENAME}-${CUT_FROM}-${CUT_TO}${SEG_SUFFIX}${EXT}';
let currentTimestamp = Date.now();
function interpolateSegmentFileName({ template, inputFileNameWithoutExt, segSuffix, ext, segNum, segLabel, cutFrom, cutTo, tags }) {
const compiled = lodashTemplate(template);
if (segSuffix) {
if (segNum > 1) {
currentTimestamp += 1;
}
}
function interpolateSegmentFileName({ template, epochMs, inputFileNameWithoutExt, segSuffix, ext, segNum, segLabel, cutFrom, cutTo, tags }) {
const compiled = lodashTemplate(template);
const data = {
FILENAME: inputFileNameWithoutExt,
@ -81,7 +75,7 @@ function interpolateSegmentFileName({ template, inputFileNameWithoutExt, segSuff
EXT: ext,
SEG_NUM: segNum,
SEG_LABEL: segLabel,
TIMESTAMP: currentTimestamp,
EPOCH_MS: String(epochMs),
CUT_FROM: cutFrom,
CUT_TO: cutTo,
SEG_TAGS: {
@ -99,6 +93,8 @@ function formatSegNum(segIndex, segments) {
}
export function generateOutSegFileNames({ segments, template, forceSafeOutputFileName, formatTimecode, isCustomFormatSelected, fileFormat, filePath, safeOutputFileName, maxLabelLength }) {
const currentTimestamp = Date.now();
return segments.map((segment, i) => {
const { start, end, name = '' } = segment;
const segNum = formatSegNum(i, segments);
@ -118,6 +114,7 @@ export function generateOutSegFileNames({ segments, template, forceSafeOutputFil
const segFileName = interpolateSegmentFileName({
template,
epochMs: currentTimestamp + i, // for convenience: give each segment a unique timestamp
segNum,
inputFileNameWithoutExt,
segSuffix: getSegSuffix(),