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