diff --git a/public/configStore.js b/public/configStore.js
index e4d077d8..992f4a5b 100644
--- a/public/configStore.js
+++ b/public/configStore.js
@@ -19,6 +19,7 @@ const defaults = {
ffmpegExperimental: false,
preserveMovData: false,
avoidNegativeTs: 'make_zero',
+ hideNotifications: undefined,
},
};
diff --git a/src/App.jsx b/src/App.jsx
index c83cf837..d57dbbc9 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -192,6 +192,8 @@ const App = memo(() => {
useEffect(() => safeSetConfig('language', language), [language]);
const [ffmpegExperimental, setFfmpegExperimental] = useState(configStore.get('ffmpegExperimental'));
useEffect(() => safeSetConfig('ffmpegExperimental', ffmpegExperimental), [ffmpegExperimental]);
+ const [hideNotifications, setHideNotifications] = useState(configStore.get('hideNotifications'));
+ useEffect(() => safeSetConfig('hideNotifications', hideNotifications), [hideNotifications]);
useEffect(() => {
i18n.changeLanguage(language || fallbackLng).catch(console.error);
@@ -255,12 +257,14 @@ const App = memo(() => {
setCopyStreamIdsForPath(path, (old) => ({ ...old, [index]: !old[index] }));
}, []);
- function toggleMute() {
+ const hideAllNotifications = hideNotifications === 'all';
+
+ const toggleMute = useCallback(() => {
setMuted((v) => {
- if (!v) toast.fire({ icon: 'info', title: i18n.t('Muted preview (exported file will not be affected)') });
+ if (!v && !hideAllNotifications) toast.fire({ icon: 'info', title: i18n.t('Muted preview (exported file will not be affected)') });
return !v;
});
- }
+ }, [hideAllNotifications]);
const seekAbs = useCallback((val) => {
const video = videoRef.current;
@@ -626,14 +630,16 @@ const App = memo(() => {
}, [assureOutDirAccess, outputDir, ffmpegExperimental, preserveMovData]);
const toggleCaptureFormat = useCallback(() => setCaptureFormat(f => (f === 'png' ? 'jpeg' : 'png')), []);
+
const toggleKeyframeCut = useCallback((showMessage) => setKeyframeCut((val) => {
const newVal = !val;
- if (showMessage) {
+ if (showMessage && !hideAllNotifications) {
if (newVal) toast.fire({ title: i18n.t('Keyframe cut enabled'), text: i18n.t('Will now cut at the nearest keyframe before the desired start cutpoint. This is recommended for most files.') });
else toast.fire({ title: i18n.t('Keyframe cut disabled'), text: i18n.t('Will now cut at the exact position, but may leave an empty portion at the beginning of the file. You may have to set the cutpoint a few frames before the next keyframe to achieve a precise cut'), timer: 7000 });
}
return newVal;
- }), []);
+ }), [hideAllNotifications]);
+
const toggleAutoMerge = useCallback(() => setAutoMerge(val => !val), []);
const togglePreserveMovData = useCallback(() => setPreserveMovData((val) => !val), []);
@@ -819,9 +825,9 @@ const App = memo(() => {
// Cleanup old
useEffect(() => () => waveform && URL.revokeObjectURL(waveform.url), [waveform]);
- function showUnsupportedFileMessage() {
- toast.fire({ timer: 13000, text: i18n.t('File not natively supported. Preview may have no audio or low quality. The final export will however be lossless with audio. You may convert it from the menu for a better preview with audio.') });
- }
+ const showUnsupportedFileMessage = useCallback(() => {
+ if (!hideAllNotifications) toast.fire({ timer: 13000, text: i18n.t('File not natively supported. Preview may have no audio or low quality. The final export will however be lossless with audio. You may convert it from the menu for a better preview with audio.') });
+ }, [hideAllNotifications]);
const createDummyVideo = useCallback(async (cod, fp) => {
const html5ifiedDummyPathDummy = getOutPath(cod, fp, 'html5ified-dummy.mkv');
@@ -834,7 +840,7 @@ const App = memo(() => {
setDummyVideoPath(html5ifiedDummyPathDummy);
setHtml5FriendlyPath();
showUnsupportedFileMessage();
- }, []);
+ }, [showUnsupportedFileMessage]);
const showPlaybackFailedMessage = () => errorToast(i18n.t('Unable to playback this file. Try to convert to supported format from the menu'));
@@ -1077,7 +1083,7 @@ const App = memo(() => {
const changePlaybackRate = useCallback((dir) => {
if (canvasPlayerEnabled) {
- toast.fire({ title: i18n.t('Unable to playback rate right now'), timer: 1000 });
+ toast.fire({ title: i18n.t('Unable to change playback rate right now'), timer: 1000 });
return;
}
@@ -1258,7 +1264,7 @@ const App = memo(() => {
} finally {
setWorking();
}
- }, [resetState, working, createDummyVideo, loadEdlFile, getEdlFilePath, getHtml5ifiedPath, loadCutSegments, enableAskForImportChapters]);
+ }, [resetState, working, createDummyVideo, loadEdlFile, getEdlFilePath, getHtml5ifiedPath, loadCutSegments, enableAskForImportChapters, showUnsupportedFileMessage]);
const toggleHelp = useCallback(() => setHelpVisible(val => !val), []);
const toggleSettings = useCallback(() => setSettingsVisible(val => !val), []);
@@ -1544,14 +1550,14 @@ const App = memo(() => {
if (error.code === MEDIA_ERR_SRC_NOT_SUPPORTED && !dummyVideoPath) {
console.log('MEDIA_ERR_SRC_NOT_SUPPORTED - trying to create dummy');
- toast.fire({ icon: 'info', text: 'This file is not natively supported. Creating a preview file...' });
+ if (!hideAllNotifications) toast.fire({ icon: 'info', text: 'This file is not natively supported. Creating a preview file...' });
if (hasVideo) {
await tryCreateDummyVideo();
} else if (hasAudio) {
await html5ifyAndLoad('fastest-audio');
}
}
- }, [tryCreateDummyVideo, fileUri, dummyVideoPath, hasVideo, hasAudio, html5ifyAndLoad]);
+ }, [tryCreateDummyVideo, fileUri, dummyVideoPath, hasVideo, hasAudio, html5ifyAndLoad, hideAllNotifications]);
useEffect(() => {
function fileOpened(event, filePaths) {
@@ -1855,12 +1861,14 @@ const App = memo(() => {
setInvertTimelineScroll={setInvertTimelineScroll}
language={language}
setLanguage={setLanguage}
+ hideNotifications={hideNotifications}
+ setHideNotifications={setHideNotifications}
AutoExportToggler={AutoExportToggler}
renderCaptureFormatButton={renderCaptureFormatButton}
onWheelTunerRequested={onWheelTunerRequested}
/>
- ), [AutoExportToggler, askBeforeClose, autoMerge, autoSaveProjectFile, customOutDir, invertCutSegments, keyframeCut, renderCaptureFormatButton, timecodeShowFrames, changeOutDir, onWheelTunerRequested, language, invertTimelineScroll, ffmpegExperimental, setFfmpegExperimental, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction]);
+ ), [AutoExportToggler, askBeforeClose, autoMerge, autoSaveProjectFile, customOutDir, invertCutSegments, keyframeCut, renderCaptureFormatButton, timecodeShowFrames, changeOutDir, onWheelTunerRequested, language, invertTimelineScroll, ffmpegExperimental, setFfmpegExperimental, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, hideNotifications, setHideNotifications]);
useEffect(() => {
if (!isStoreBuild) loadMifiLink().then(setMifiLink);
diff --git a/src/Settings.jsx b/src/Settings.jsx
index 854dd5bb..1503612e 100644
--- a/src/Settings.jsx
+++ b/src/Settings.jsx
@@ -9,6 +9,7 @@ const Settings = memo(({
AutoExportToggler, renderCaptureFormatButton, onWheelTunerRequested, language, setLanguage,
invertTimelineScroll, setInvertTimelineScroll, ffmpegExperimental, setFfmpegExperimental,
enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction,
+ hideNotifications, setHideNotifications,
}) => {
const { t } = useTranslation();
@@ -196,6 +197,17 @@ const Settings = memo(({
+
+ {t('Hide informational notifications?')}
+
+ setHideNotifications(e.target.checked ? 'all' : undefined)}
+ />
+
+
+
{t('Ask about what to do when opening a new file when another file is already already open?')}