toast.fire({timer:10000,icon:'warning',title:'This video is not natively supported', text:'This means that there is no audio in the preview and it has low quality. The final export operation will however be lossless and contains audio!'});
toast.fire({timer:10000,icon:'warning',title:i18n.t('This video is not natively supported'), text:i18n.t('This means that there is no audio in the preview and it has low quality. The final export operation will however be lossless and contains audio!')});
}
constcreateDummyVideo=useCallback(async(fp)=>{
@ -779,7 +788,7 @@ const App = memo(() => {
awaitcreateDummyVideo(filePath);
}catch(err){
console.error(err);
errorToast('Failed to playback this file. Try to convert to friendly format from the menu');
errorToast(i18n.t('Failed to playback this file. Try to convert to friendly format from the menu'));
}finally{
setWorking(false);
}
@ -807,7 +816,7 @@ const App = memo(() => {
if(!filePath)return;
//eslint-disable-next-lineno-alert
if(working||!window.confirm(`Are you sure you want to move the source file to trash? ${filePath}`))return;
if(working||!window.confirm(`${i18n.t('Are you sure you want to move the source file to trash?')}${filePath}`))return;
toast.fire({icon:'error',title:`Failed to trash source file:${err.message}`});
toast.fire({icon:'error',title:`${i18n.t('Failed to trash source file:')}${err.message}`});
}finally{
resetState();
}
@ -826,27 +835,27 @@ const App = memo(() => {
constcutClick=useCallback(async()=>{
if(working){
errorToast('I\'m busy');
errorToast(i18n.t('I\'m busy'));
return;
}
if(haveInvalidSegs){
errorToast('Start time must be before end time');
errorToast(i18n.t('Start time must be before end time'));
return;
}
if(numStreamsToCopy===0){
errorToast('No tracks to export!');
errorToast(i18n.t('No tracks to export!'));
return;
}
if(!outSegments){
errorToast('No segments to export!');
errorToast(i18n.t('No segments to export!'));
return;
}
if(outSegments.length<1){
errorToast('No segments to export');
errorToast(i18n.t('No segments to export'));
return;
}
@ -888,7 +897,8 @@ const App = memo(() => {
}
}
toast.fire({timer:10000,icon:'success',title:`Export completed! Go to settings to view the ffmpeg commands that were executed. If output does not look right, try to toggle "Keyframe cut" or try a different output format (e.g. matroska). Output file(s) can be found at: ${outputDir}.${exportExtraStreams?' Extra unprocessable streams were exported to separate files.':''}`});
constextraStreamsMsg=exportExtraStreams?`${i18n.t('Extra unprocessable streams were exported to separate files.')}`:'';
toast.fire({timer:10000,icon:'success',title:`${i18n.t('Export completed! Go to settings to view the ffmpeg commands that were executed. If output does not look right, try to toggle "Keyframe cut" or try a different output format (e.g. matroska). Output file(s) can be found at:')}${outputDir}.${extraStreamsMsg}`});
}catch(err){
console.error('stdout:',err.stdout);
console.error('stderr:',err.stderr);
@ -913,15 +923,15 @@ const App = memo(() => {
constcapture=useCallback(async()=>{
if(!filePath)return;
if(html5FriendlyPath||dummyVideoPath){
errorToast('Capture frame from this video not yet implemented');
errorToast(i18n.t('Capture frame from this video not yet implemented'));
<FaClipboardstyle={{cursor:'pointer'}}title="Copy to clipboard"onClick={()=>{clipboard.writeText(command);toast.fire({timer:2000,icon:'success',title:'Copied to clipboard'});}}/>{command}
<FaClipboardstyle={{cursor:'pointer'}}title={t('Copy to clipboard')}onClick={()=>{clipboard.writeText(command);toast.fire({timer:2000,icon:'success',title:t('Copied to clipboard')});}}/>{command}
</div>
))}
</div>
):(
<p>{t('The last executed ffmpeg commands will show up here after you run operations. You can copy them to clipboard and modify them to your needs before running on your command line.')}</p>
{t('Extract unprocessable tracks to separate files or discard them?')}<br/>
{t('(data tracks such as GoPro GPS, telemetry etc. are not copied over by default because ffmpeg cannot cut them, thus they will cause the media duration to stay the same after cutting video/audio)')}
</KeyCell>
<Table.TextCell>
<AutoExportToggler/>
@ -84,12 +104,12 @@ const Settings = memo(({
<Row>
<KeyCell>
Auto save project file?<br/>
The project will be stored along with the output files as a CSV file
{t('Auto save project file?')}<br/>
{t('The project will be stored along with the output files as a CSV file')}
returnerrorToast(`Failed to run ffmpeg:${err.stack}`);
returnerrorToast(`${i18n.t('Failed to run ffmpeg:')}${err.stack}`);
}
exportfunctionsetFileNameTitle(filePath){
@ -98,8 +99,8 @@ export function filenamify(name) {
exportasyncfunctionpromptTimeOffset(inputValue){
const{value}=awaitSwal.fire({
title:'Set custom start time offset',
text:'Instead of video apparently starting at 0, you can offset by a specified value (useful for viewing/cutting videos according to timecodes)',
title:i18n.t('Set custom start time offset'),
text:i18n.t('Instead of video apparently starting at 0, you can offset by a specified value (useful for viewing/cutting videos according to timecodes)'),