mirror of https://github.com/dessant/buster
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
4.7 KiB
JavaScript
221 lines
4.7 KiB
JavaScript
import browser from 'webextension-polyfill';
|
|
import Bowser from 'bowser';
|
|
|
|
import {targetEnv} from 'utils/config';
|
|
|
|
const getText = browser.i18n.getMessage;
|
|
|
|
function createTab(
|
|
url,
|
|
{index = null, active = true, openerTabId = null} = {}
|
|
) {
|
|
const props = {url, active};
|
|
if (index !== null) {
|
|
props.index = index;
|
|
}
|
|
if (openerTabId !== null && ['chrome', 'edge', 'opera'].includes(targetEnv)) {
|
|
props.openerTabId = openerTabId;
|
|
}
|
|
return browser.tabs.create(props);
|
|
}
|
|
|
|
async function isAndroid() {
|
|
const {os} = await browser.runtime.getPlatformInfo();
|
|
return os === 'android';
|
|
}
|
|
|
|
async function getPlatform() {
|
|
let {os, arch} = await browser.runtime.getPlatformInfo();
|
|
if (os === 'win') {
|
|
os = 'windows';
|
|
} else if (os === 'mac') {
|
|
os = 'macos';
|
|
}
|
|
|
|
if (arch === 'x86-32') {
|
|
arch = '386';
|
|
} else if (arch === 'x86-64' || (arch.startsWith('arm') && os === 'macos')) {
|
|
arch = 'amd64';
|
|
}
|
|
|
|
return {os, arch};
|
|
}
|
|
|
|
async function getBrowser() {
|
|
let name, version;
|
|
try {
|
|
({name, version} = await browser.runtime.getBrowserInfo());
|
|
} catch (err) {}
|
|
|
|
if (!name) {
|
|
({name, version} = Bowser.getParser(
|
|
window.navigator.userAgent
|
|
).getBrowser());
|
|
}
|
|
|
|
name = name.toLowerCase();
|
|
|
|
return {name, version};
|
|
}
|
|
|
|
async function getActiveTab() {
|
|
const [tab] = await browser.tabs.query({
|
|
lastFocusedWindow: true,
|
|
active: true
|
|
});
|
|
return tab;
|
|
}
|
|
|
|
function waitForElement(selector, {timeout = 10000} = {}) {
|
|
return new Promise(resolve => {
|
|
const el = document.querySelector(selector);
|
|
if (el) {
|
|
resolve(el);
|
|
return;
|
|
}
|
|
|
|
const observer = new MutationObserver(function (mutations, obs) {
|
|
const el = document.querySelector(selector);
|
|
if (el) {
|
|
obs.disconnect();
|
|
window.clearTimeout(timeoutId);
|
|
resolve(el);
|
|
}
|
|
});
|
|
|
|
observer.observe(document, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
|
|
const timeoutId = window.setTimeout(function () {
|
|
observer.disconnect();
|
|
resolve();
|
|
}, timeout);
|
|
});
|
|
}
|
|
|
|
function arrayBufferToBase64(buffer) {
|
|
let binary = '';
|
|
const bytes = new Uint8Array(buffer);
|
|
const len = bytes.byteLength;
|
|
for (var i = 0; i < len; i++) {
|
|
binary += String.fromCharCode(bytes[i]);
|
|
}
|
|
|
|
return window.btoa(binary);
|
|
}
|
|
|
|
function executeCode(string, tabId, frameId = 0, runAt = 'document_start') {
|
|
return browser.tabs.executeScript(tabId, {
|
|
frameId: frameId,
|
|
runAt: runAt,
|
|
code: string
|
|
});
|
|
}
|
|
|
|
function executeFile(file, tabId, frameId = 0, runAt = 'document_start') {
|
|
return browser.tabs.executeScript(tabId, {
|
|
frameId: frameId,
|
|
runAt: runAt,
|
|
file: file
|
|
});
|
|
}
|
|
|
|
async function scriptsAllowed(tabId, frameId = 0) {
|
|
try {
|
|
await browser.tabs.executeScript(tabId, {
|
|
frameId: frameId,
|
|
runAt: 'document_start',
|
|
code: 'true;'
|
|
});
|
|
return true;
|
|
} catch (err) {}
|
|
}
|
|
|
|
async function functionInContext(
|
|
functionName,
|
|
tabId,
|
|
frameId = 0,
|
|
runAt = 'document_start'
|
|
) {
|
|
const [isFunction] = await executeCode(
|
|
`typeof ${functionName} === "function"`,
|
|
tabId,
|
|
frameId,
|
|
runAt
|
|
);
|
|
return isFunction;
|
|
}
|
|
|
|
function getRandomInt(min, max) {
|
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
}
|
|
|
|
function getRandomFloat(min, max) {
|
|
return Math.random() * (max - min) + min;
|
|
}
|
|
|
|
function sleep(ms) {
|
|
return new Promise(resolve => window.setTimeout(resolve, ms));
|
|
}
|
|
|
|
async function normalizeAudio(buffer) {
|
|
const ctx = new AudioContext();
|
|
const audioBuffer = await ctx.decodeAudioData(buffer);
|
|
ctx.close();
|
|
|
|
const offlineCtx = new OfflineAudioContext(
|
|
1,
|
|
audioBuffer.duration * 16000,
|
|
16000
|
|
);
|
|
const source = offlineCtx.createBufferSource();
|
|
source.connect(offlineCtx.destination);
|
|
source.buffer = audioBuffer;
|
|
source.start();
|
|
|
|
return offlineCtx.startRendering();
|
|
}
|
|
|
|
async function sliceAudio({audioBuffer, start, end}) {
|
|
const sampleRate = audioBuffer.sampleRate;
|
|
const channels = audioBuffer.numberOfChannels;
|
|
|
|
const startOffset = sampleRate * start;
|
|
const endOffset = sampleRate * end;
|
|
const frameCount = endOffset - startOffset;
|
|
|
|
const ctx = new AudioContext();
|
|
const audioSlice = ctx.createBuffer(channels, frameCount, sampleRate);
|
|
ctx.close();
|
|
|
|
const tempArray = new Float32Array(frameCount);
|
|
for (var channel = 0; channel < channels; channel++) {
|
|
audioBuffer.copyFromChannel(tempArray, channel, startOffset);
|
|
audioSlice.copyToChannel(tempArray, channel, 0);
|
|
}
|
|
|
|
return audioSlice;
|
|
}
|
|
|
|
export {
|
|
getText,
|
|
createTab,
|
|
isAndroid,
|
|
getPlatform,
|
|
getBrowser,
|
|
getActiveTab,
|
|
waitForElement,
|
|
arrayBufferToBase64,
|
|
executeCode,
|
|
executeFile,
|
|
scriptsAllowed,
|
|
functionInContext,
|
|
getRandomInt,
|
|
getRandomFloat,
|
|
sleep,
|
|
normalizeAudio,
|
|
sliceAudio
|
|
};
|