From faa07424fb9e3f3c4542f0151bf1bc3c6c788efd Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Mon, 2 Jan 2023 17:17:41 +0800 Subject: [PATCH] rewrite checking logic replace axios with ky and add fake app check --- package.json | 2 +- src/App.jsx | 25 ++++--------------------- src/BottomBar.jsx | 11 +++++------ src/ffmpeg.js | 3 ++- src/mifi.js | 32 +++++++++++++++++++++++++++----- src/util.js | 30 ++++++++++++++++++++++++++++++ yarn.lock | 11 +++++++++-- 7 files changed, 78 insertions(+), 36 deletions(-) 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