mirror of https://github.com/mifi/lossless-cut
use js expressions instead of mathjs #2002
parent
096db54f11
commit
ec3e626693
@ -0,0 +1,11 @@
|
||||
# Expressions
|
||||
|
||||
## Select segments by expression
|
||||
|
||||
LosslessCut has support for normal JavaScript expressions. You will be given a variable `segment` and can create an expression that returns `true` or `false`. For example to select all segments with a duration of less than 5 seconds use this expression:
|
||||
|
||||
```js
|
||||
segment.duration < 5
|
||||
```
|
||||
|
||||
See more examples in-app.
|
||||
@ -0,0 +1,51 @@
|
||||
const workerUrl = new URL('evalWorker.js', import.meta.url);
|
||||
|
||||
// https://v3.vitejs.dev/guide/features.html#web-workers
|
||||
// todo terminate() and recreate in case of error?
|
||||
const worker = new Worker(workerUrl);
|
||||
|
||||
let lastRequestId = 0;
|
||||
|
||||
export default async function safeishEval(code: string, context: unknown) {
|
||||
return new Promise((resolve, reject) => {
|
||||
lastRequestId += 1;
|
||||
const id = lastRequestId;
|
||||
|
||||
// console.log({ lastRequestId, code, context })
|
||||
|
||||
function cleanup() {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
worker.removeEventListener('message', onMessage);
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
worker.removeEventListener('messageerror', onMessageerror);
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
worker.removeEventListener('error', onError);
|
||||
}
|
||||
|
||||
function onMessage({ data: { id: responseId, error, data } }) {
|
||||
// console.log('message', { responseId, error, data })
|
||||
|
||||
if (responseId === id) {
|
||||
cleanup();
|
||||
if (error) reject(new Error(error));
|
||||
else resolve(data);
|
||||
}
|
||||
}
|
||||
|
||||
function onMessageerror() {
|
||||
cleanup();
|
||||
reject(new Error('safeishEval messageerror'));
|
||||
}
|
||||
|
||||
function onError(err: ErrorEvent) {
|
||||
cleanup();
|
||||
reject(new Error(`safeishEval error: ${err.message}`));
|
||||
}
|
||||
|
||||
worker.addEventListener('message', onMessage);
|
||||
worker.addEventListener('messageerror', onMessageerror);
|
||||
worker.addEventListener('error', onError);
|
||||
|
||||
worker.postMessage({ id, code, context: JSON.stringify(context) });
|
||||
});
|
||||
}
|
||||
@ -0,0 +1,138 @@
|
||||
// eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
|
||||
const myGlobal = this;
|
||||
|
||||
// https://stackoverflow.com/a/10796616/6519037
|
||||
// https://github.com/Zirak/SO-ChatBot/blob/master/source/eval.js
|
||||
// https://github.com/Zirak/SO-ChatBot/blob/master/source/codeWorker.js
|
||||
|
||||
const wl = {
|
||||
self: 1,
|
||||
onmessage: 1,
|
||||
postMessage: 1,
|
||||
global: 1,
|
||||
wl: 1,
|
||||
eval: 1,
|
||||
Array: 1,
|
||||
Boolean: 1,
|
||||
Date: 1,
|
||||
Function: 1,
|
||||
Number: 1,
|
||||
Object: 1,
|
||||
RegExp: 1,
|
||||
String: 1,
|
||||
Error: 1,
|
||||
EvalError: 1,
|
||||
RangeError: 1,
|
||||
ReferenceError: 1,
|
||||
SyntaxError: 1,
|
||||
TypeError: 1,
|
||||
URIError: 1,
|
||||
decodeURI: 1,
|
||||
decodeURIComponent: 1,
|
||||
encodeURI: 1,
|
||||
encodeURIComponent: 1,
|
||||
isFinite: 1,
|
||||
isNaN: 1,
|
||||
parseFloat: 1,
|
||||
parseInt: 1,
|
||||
Infinity: 1,
|
||||
JSON: 1,
|
||||
Math: 1,
|
||||
NaN: 1,
|
||||
undefined: 1,
|
||||
|
||||
// Chrome errors if you attempt to write over either of these properties, so put them in the whitelist
|
||||
// https://github.com/owl-factory/lantern/blob/addda28034d5d30a7ea720646aa56fefa8f05cf4/archive/src/nodes/sandbox/workers/sandboxed-code.worker.ts#L47
|
||||
TEMPORARY: 1,
|
||||
PERSISTENT: 1,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line prefer-arrow-callback, func-names
|
||||
Object.getOwnPropertyNames(myGlobal).forEach(function (prop) {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!wl.hasOwnProperty(prop)) {
|
||||
Object.defineProperty(myGlobal, prop, {
|
||||
// eslint-disable-next-line func-names, object-shorthand
|
||||
get: function () {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw `Security Exception: cannot access ${prop}`;
|
||||
},
|
||||
configurable: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-proto, prefer-arrow-callback, func-names
|
||||
Object.getOwnPropertyNames(myGlobal.__proto__).forEach(function (prop) {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!wl.hasOwnProperty(prop)) {
|
||||
// eslint-disable-next-line no-proto
|
||||
Object.defineProperty(myGlobal.__proto__, prop, {
|
||||
// eslint-disable-next-line func-names, object-shorthand
|
||||
get: function () {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw `Security Exception: cannot access ${prop}`;
|
||||
},
|
||||
configurable: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Array(5000000000).join("adasdadadasd") instantly crashing some browser tabs
|
||||
// eslint-disable-next-line no-extend-native
|
||||
Object.defineProperty(Array.prototype, 'join', {
|
||||
writable: false,
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
// eslint-disable-next-line wrap-iife, func-names
|
||||
value: function (old) {
|
||||
// eslint-disable-next-line func-names
|
||||
return function (arg) {
|
||||
// @ts-expect-error dunno how to fix
|
||||
if (this.length > 500 || (arg && arg.length > 500)) {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw 'Exception: too many items';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line unicorn/prefer-reflect-apply, prefer-rest-params
|
||||
// @ts-expect-error dunno how to fix
|
||||
return old.apply(this, arg);
|
||||
};
|
||||
}(Array.prototype.join),
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
https://github.com/Zirak/SO-ChatBot/blob/accbfb4b8738781afaf4f080a6bb0337e13f7c25/source/codeWorker.js#L87
|
||||
|
||||
DOM specification doesn't define an enumerable `fetch` function object on
|
||||
the global object so we add the property here, and the following code will
|
||||
blacklist it. (`fetch` descends from `GlobalFetch`, and is thus present in
|
||||
worker code as well)
|
||||
Just in case someone runs the bot on some old browser where `fetch` is not
|
||||
defined anyways, this will have no effect.
|
||||
Reason for blacklisting fetch: well, same as XHR.
|
||||
*/
|
||||
// @ts-expect-error expected
|
||||
myGlobal.fetch = undefined;
|
||||
|
||||
|
||||
// eslint-disable-next-line wrap-iife, func-names
|
||||
(function () {
|
||||
onmessage = (event) => {
|
||||
// eslint-disable-next-line strict, lines-around-directive
|
||||
'use strict';
|
||||
|
||||
const { code, id, context: contextStr } = event.data;
|
||||
const context = { ...JSON.parse(contextStr) };
|
||||
|
||||
try {
|
||||
// https://stackoverflow.com/questions/8403108/calling-eval-in-particular-context
|
||||
// eslint-disable-next-line unicorn/new-for-builtins, no-new-func
|
||||
const result = Function(`\nwith (this) { return (${code}); }`).call(context);
|
||||
postMessage({ id, data: result });
|
||||
} catch (e) {
|
||||
postMessage({ id, error: `${e}` });
|
||||
}
|
||||
};
|
||||
})();
|
||||
Loading…
Reference in New Issue