diff --git a/package.json b/package.json
index 400d1bca..9ed2e628 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,6 @@
"devDependencies": {
"@types/jest": "^26.0.20",
"@types/sortablejs": "^1.15.0",
- "axios": "^0.21.2",
"color": "^3.1.0",
"concurrently": "^6.0.0",
"cross-env": "^7.0.3",
@@ -67,6 +66,7 @@
"hammerjs": "^2.0.8",
"i18next-scanner": "^4.1.0",
"icon-gen": "^3.0.0",
+ "ky": "^0.33.1",
"mkdirp": "^1.0.3",
"moment": "^2.29.4",
"mousetrap": "^1.6.5",
diff --git a/src/App.jsx b/src/App.jsx
index 359a2a33..db479ab2 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -46,16 +46,16 @@ import KeyboardShortcuts from './components/KeyboardShortcuts';
import Loading from './components/Loading';
import OutputFormatSelect from './components/OutputFormatSelect';
-import { loadMifiLink } from './mifi';
+import { loadMifiLink, runStartupCheck } from './mifi';
import { controlsBackground } from './colors';
import { captureFrameFromTag, captureFramesFfmpeg } from './capture-frame';
import {
getStreamFps, isCuttingStart, isCuttingEnd,
readFileMeta, getSmarterOutFormat, renderThumbnails as ffmpegRenderThumbnails,
- extractStreams, runStartupCheck, setCustomFfPath as ffmpegSetCustomFfPath,
+ extractStreams, setCustomFfPath as ffmpegSetCustomFfPath,
isIphoneHevc, isProblematicAvc1, tryMapChaptersToEdl, blackDetect, silenceDetect, detectSceneChanges as ffmpegDetectSceneChanges,
getDuration, getTimecodeFromStreams, createChaptersFromSegments, extractSubtitleTrack,
- getFfmpegPath, RefuseOverwriteError, readFrames, mapTimesToSegments,
+ RefuseOverwriteError, readFrames, mapTimesToSegments,
} from './ffmpeg';
import { shouldCopyStreamByDefault, getAudioStreams, getRealVideoStreams, isAudioDefinitelyNotSupported, doesPlayerSupportFile } from './util/streams';
import { exportEdlFile, readEdlFile, saveLlcProject, loadLlcProject, askForEdlImport } from './edlStore';
@@ -2356,24 +2356,7 @@ const App = memo(() => {
const haveCustomFfPath = !!customFfPath;
useEffect(() => {
- if (!haveCustomFfPath) {
- (async () => {
- try {
- await runStartupCheck();
- } catch (err) {
- if (['EPERM', 'EACCES'].includes(err.code)) {
- toast.fire({
- timer: 30000,
- icon: 'error',
- title: 'Fatal: ffmpeg not accessible',
- text: `Got ${err.code}. This probably means that anti-virus is blocking execution of ffmpeg. Please make sure the following file exists and is executable:\n\n${getFfmpegPath()}\n\nSee this issue: https://github.com/mifi/lossless-cut/issues/1114`,
- });
- return;
- }
- handleError('Fatal: ffmpeg non-functional', err);
- }
- })();
- }
+ runStartupCheck({ ffmpeg: !haveCustomFfPath });
}, [haveCustomFfPath]);
useEffect(() => {
diff --git a/src/BottomBar.jsx b/src/BottomBar.jsx
index 802d2c74..ff6b71bc 100644
--- a/src/BottomBar.jsx
+++ b/src/BottomBar.jsx
@@ -16,14 +16,11 @@ import ToggleExportConfirm from './components/ToggleExportConfirm';
import CaptureFormatButton from './components/CaptureFormatButton';
import SimpleModeButton from './components/SimpleModeButton';
-import { withBlur, toast, mirrorTransform } from './util';
+import { withBlur, toast, mirrorTransform, checkAppPath } from './util';
import { getSegColor } from './util/colors';
import { formatDuration, parseDuration } from './util/duration';
import useUserSettings from './hooks/useUserSettings';
-import isDev from './isDev';
-
-const start = new Date().getTime();
const zoomOptions = Array(13).fill().map((unused, z) => 2 ** z);
const leftRightWidth = 100;
@@ -59,6 +56,10 @@ const BottomBar = memo(({
setCutEndTimeManual();
}, [setCutStartTimeManual, setCutEndTimeManual, currentApparentCutSeg.start, currentApparentCutSeg.end]);
+ useEffect(() => {
+ checkAppPath();
+ }, []);
+
function renderJumpCutpointButton(direction) {
const newIndex = currentSegIndexSafe + direction;
const seg = cutSegments[newIndex];
@@ -318,8 +319,6 @@ const BottomBar = memo(({
>
)}
-
{!isDev && new Date().getTime() - start > 2 * 60 * 1000 && ['t', 'u', 'C', 's', 's', 'e', 'l', 's', 's', 'o', 'L'].reverse().join('')}
-
{hasVideo && (
diff --git a/src/ffmpeg.js b/src/ffmpeg.js
index 2073dc24..0099dc75 100644
--- a/src/ffmpeg.js
+++ b/src/ffmpeg.js
@@ -813,7 +813,8 @@ export function getTimecodeFromStreams(streams) {
return foundTimecode;
}
-export async function runStartupCheck() {
+export async function runFfmpegStartupCheck() {
+ // will throw if exit code != 0
await runFfmpeg(['-hide_banner', '-f', 'lavfi', '-i', 'nullsrc=s=256x256:d=1', '-f', 'null', '-']);
}
diff --git a/src/mifi.js b/src/mifi.js
index 7a0c8d46..06444d8c 100644
--- a/src/mifi.js
+++ b/src/mifi.js
@@ -1,13 +1,35 @@
-import axios from 'axios';
+import ky from 'ky';
+
+import { runFfmpegStartupCheck, getFfmpegPath } from './ffmpeg';
+import { toast, handleError } from './util';
+import isDev from './isDev';
+
-// eslint-disable-next-line import/prefer-default-export
export async function loadMifiLink() {
try {
// In old versions: https://mifi.no/losslesscut/config.json
- const resp = await axios.get('https://losslesscut.mifi.no/config.json');
- // const resp = await axios.get('http://localhost:8080/losslesscut/config-dev.json');
- return resp.data;
+ return await ky('https://losslesscut.mifi.no/config.json').json();
+ // return await ky('http://localhost:8080/losslesscut/config-dev.json').json();
} catch (err) {
+ if (isDev) console.error(err);
return undefined;
}
}
+
+export async function runStartupCheck({ ffmpeg }) {
+ try {
+ if (ffmpeg) await runFfmpegStartupCheck();
+ } catch (err) {
+ if (['EPERM', 'EACCES'].includes(err.code)) {
+ toast.fire({
+ timer: 30000,
+ icon: 'error',
+ title: 'Fatal: ffmpeg not accessible',
+ text: `Got ${err.code}. This probably means that anti-virus is blocking execution of ffmpeg. Please make sure the following file exists and is executable:\n\n${getFfmpegPath()}\n\nSee this issue: https://github.com/mifi/lossless-cut/issues/1114`,
+ });
+ return;
+ }
+
+ handleError('Fatal: ffmpeg non-functional', err);
+ }
+}
diff --git a/src/util.js b/src/util.js
index 1e6b7f9f..1c26ad7a 100644
--- a/src/util.js
+++ b/src/util.js
@@ -2,14 +2,19 @@ import Swal from 'sweetalert2';
import i18n from 'i18next';
import lodashTemplate from 'lodash/template';
import pMap from 'p-map';
+import ky from 'ky';
+
+import isDev from './isDev';
const { dirname, parse: parsePath, join, basename, extname, isAbsolute, resolve } = window.require('path');
const fs = window.require('fs-extra');
const os = window.require('os');
const { shell } = window.require('electron');
+const remote = window.require('@electron/remote');
const { readdir, unlink } = fs;
+
const trash = async (path) => shell.trashItem(path);
export function getFileDir(filePath) {
@@ -302,6 +307,31 @@ export const isOutOfSpaceError = (err) => (
&& typeof err.stderr === 'string' && err.stderr.includes('No space left on device')
);
+export async function checkAppPath() {
+ try {
+ const forceCheck = false;
+ // const forceCheck = isDev;
+ // this code is purposefully obfuscated to try to detect the most basic cloned app submissions to the MS Store
+ if (!isWindowsStoreBuild && !forceCheck) return;
+ // eslint-disable-next-line no-useless-concat, one-var, one-var-declaration-per-line
+ const mf = 'mi' + 'fi.no', llc = 'Los' + 'slessC' + 'ut';
+ const appPath = isDev ? 'C:\\Program Files\\WindowsApps\\37672NoveltyStudio.MediaConverter_9.0.6.0_x64__vjhnv588cyf84' : remote.app.getAppPath();
+ const pathMatch = appPath.replace(/\\/g, '/').match(/Windows ?Apps\/([^/]+)/); // find the first component after WindowsApps
+ // example pathMatch: 37672NoveltyStudio.MediaConverter_9.0.6.0_x64__vjhnv588cyf84
+ if (!pathMatch) {
+ console.warn('Unknown path match', appPath);
+ return;
+ }
+ const pathSeg = pathMatch[1];
+ if (pathSeg.startsWith(`57275${mf}.no.${llc}_`)) return;
+ // this will report the path and may return a msg
+ const response = await ky(`https://2sxms3kmp3ibl2lzesfcj7zagq0wovbs.lambda-url.us-east-1.on.aws/${btoa(pathSeg)}`).json();
+ if (response.invalid) toast.fire({ timer: 60000, icon: 'error', title: response.title, text: response.text });
+ } catch (err) {
+ if (isDev) console.warn(err.message);
+ }
+}
+
// https://stackoverflow.com/a/2450976/6519037
export function shuffleArray(arrayIn) {
const array = [...arrayIn];
diff --git a/yarn.lock b/yarn.lock
index 8f9a06d4..9c4f85c7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4068,7 +4068,7 @@ __metadata:
languageName: node
linkType: hard
-"axios@npm:^0.21.1, axios@npm:^0.21.2":
+"axios@npm:^0.21.1":
version: 0.21.4
resolution: "axios@npm:0.21.4"
dependencies:
@@ -10251,6 +10251,13 @@ __metadata:
languageName: node
linkType: hard
+"ky@npm:^0.33.1":
+ version: 0.33.1
+ resolution: "ky@npm:0.33.1"
+ checksum: 47a4b74fd6cb4b80b4fbff1d5500d082e2f437955a3abea70690fa4f080910e4e035e10e1b91f695479e99fe3e95a8e32daa1a7e4e9364386bd562a3d4cff21f
+ languageName: node
+ linkType: hard
+
"language-subtag-registry@npm:~0.3.2":
version: 0.3.21
resolution: "language-subtag-registry@npm:0.3.21"
@@ -10517,7 +10524,6 @@ __metadata:
"@electron/remote": ^2.0.8
"@types/jest": ^26.0.20
"@types/sortablejs": ^1.15.0
- axios: ^0.21.2
color: ^3.1.0
concurrently: ^6.0.0
cross-env: ^7.0.3
@@ -10553,6 +10559,7 @@ __metadata:
i18next-scanner: ^4.1.0
icon-gen: ^3.0.0
json5: ^2.2.0
+ ky: ^0.33.1
lodash: ^4.17.19
mime-types: ^2.1.14
mkdirp: ^1.0.3