inital (feature: post likes)
This commit is contained in:
commit
3bdb2ebef5
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
rs/target
|
||||||
|
/unpacked_*
|
||||||
|
*.rq
|
||||||
30
build.sh
Executable file
30
build.sh
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
## --release or --dev - exclude/include debug info
|
||||||
|
## --no-typescript - disable .d.ts files output
|
||||||
|
## --out-dir - where to write the compiled files
|
||||||
|
## --out-name - force output file names
|
||||||
|
## --target - always use "web"!
|
||||||
|
## See https://rustwasm.github.io/wasm-pack/book/commands/build.html
|
||||||
|
echo Building wasm module...
|
||||||
|
wasm-pack build rs --dev --no-typescript --out-dir "../ext/js/wasm" --out-name "wasm_mod" --target web
|
||||||
|
|
||||||
|
## wasm-pack creates bunch of useless files:
|
||||||
|
echo Removing trash files...
|
||||||
|
rm -f ext/js/wasm/.gitignore
|
||||||
|
rm -f ext/js/wasm/package.json
|
||||||
|
|
||||||
|
## create chrome package and exclude manifest for firefox
|
||||||
|
## see ReadMe for more info on manifest config
|
||||||
|
## subshell call with cd is required to avoid placing /extension/ folder as the root
|
||||||
|
rm -f chrome.zip && \
|
||||||
|
(cd ext && zip -rq ../chrome.zip . -x manifest_ff.json -x manifest.json) && \
|
||||||
|
printf "@ manifest_cr.json\n@=manifest.json\n" | zipnote -w chrome.zip && \
|
||||||
|
echo Chrome package: chrome.zip
|
||||||
|
|
||||||
|
## create firefox package, exclude chrome manifest and rename FF manifest to its default file name
|
||||||
|
rm -f firefox.zip && \
|
||||||
|
(cd ext && zip -rq ../firefox.zip . -x manifest_cr.json -x manifest.json) && \
|
||||||
|
printf "@ manifest_ff.json\n@=manifest.json\n" | zipnote -w firefox.zip && \
|
||||||
|
echo Firefox package: firefox.zip
|
||||||
|
|
||||||
|
|
||||||
|
rm -rf unpacked_ch && unzip chrome.zip -d unpacked_ch
|
||||||
BIN
chrome.zip
Normal file
BIN
chrome.zip
Normal file
Binary file not shown.
BIN
ext/assets/InterTight-Italic-VariableFont_wght.ttf
Normal file
BIN
ext/assets/InterTight-Italic-VariableFont_wght.ttf
Normal file
Binary file not shown.
BIN
ext/assets/InterTight-VariableFont_wght.ttf
Normal file
BIN
ext/assets/InterTight-VariableFont_wght.ttf
Normal file
Binary file not shown.
BIN
ext/assets/Inter_Tight.zip
Normal file
BIN
ext/assets/Inter_Tight.zip
Normal file
Binary file not shown.
BIN
ext/assets/icon.png
Normal file
BIN
ext/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
ext/assets/icon128.png
Normal file
BIN
ext/assets/icon128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
BIN
ext/assets/icon16.png
Normal file
BIN
ext/assets/icon16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 505 B |
BIN
ext/assets/icon32.png
Normal file
BIN
ext/assets/icon32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
ext/assets/icon48.png
Normal file
BIN
ext/assets/icon48.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
ext/assets/static/InterTight-Medium.ttf
Normal file
BIN
ext/assets/static/InterTight-Medium.ttf
Normal file
Binary file not shown.
57
ext/js/background.js
Normal file
57
ext/js/background.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import initWasmModule, { post, like } from './wasm/wasm_mod.js';
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
await initWasmModule();
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
chrome.runtime.onMessage.addListener(async (request, sender, _) => {
|
||||||
|
if (request?.action) {
|
||||||
|
|
||||||
|
const storage = await chrome.storage.local.get();
|
||||||
|
|
||||||
|
if (request.action == "like") {
|
||||||
|
const { rect, ratio, by, me, id, is_private } = request;
|
||||||
|
|
||||||
|
if (sender.tab) {
|
||||||
|
// make a screenshot
|
||||||
|
|
||||||
|
if (storage.screenshot) {
|
||||||
|
setTimeout(async function () {
|
||||||
|
const screenshot = await chrome.tabs.captureVisibleTab(null, { format: "png" });
|
||||||
|
|
||||||
|
const canvas = new OffscreenCanvas(rect.width, rect.height);
|
||||||
|
|
||||||
|
const bytes = atob(screenshot.replace("data:image/png;base64,", ""));
|
||||||
|
const array_buf = new ArrayBuffer(bytes.length);
|
||||||
|
const uint_arr = new Uint8Array(array_buf);
|
||||||
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
|
uint_arr[i] = bytes.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob([array_buf], { type: "image/png" });
|
||||||
|
const top = Math.max(rect.top, 0);
|
||||||
|
const bitmap = await createImageBitmap(
|
||||||
|
blob,
|
||||||
|
Math.ceil(rect.left * ratio),
|
||||||
|
Math.ceil(top * ratio),
|
||||||
|
rect.width * ratio,
|
||||||
|
(rect.bottom - top) * ratio // if top of the image is outside of the viewport, subtract offset from height
|
||||||
|
);
|
||||||
|
|
||||||
|
canvas.getContext('bitmaprenderer').transferFromImageBitmap(bitmap);
|
||||||
|
const cropped_blob = await canvas.convertToBlob(); // slllloooow. kinda. 300ms.
|
||||||
|
|
||||||
|
const cropped_bytes = await cropped_blob.arrayBuffer();
|
||||||
|
const cropped_bytes_uint8 = new Uint8Array(cropped_bytes);
|
||||||
|
|
||||||
|
await like({ id, by, me, is_private }, cropped_bytes_uint8);
|
||||||
|
}, storage.delay || 1)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
await like({ id, by, me, is_private });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
58
ext/js/content-script.js
Normal file
58
ext/js/content-script.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
const obs_cb = (ml, _) => {
|
||||||
|
|
||||||
|
ml.forEach((mutation) => {
|
||||||
|
if (mutation.type === "attributes" && mutation.attributeName === "data-testid") {
|
||||||
|
const old = mutation.oldValue.toLocaleLowerCase();
|
||||||
|
const _new = mutation.target.dataset.testid.toLocaleLowerCase();
|
||||||
|
|
||||||
|
if (old == "like" && _new == "unlike") {
|
||||||
|
const tweet = mutation.target.closest('article[data-testid="tweet"]');
|
||||||
|
|
||||||
|
if (tweet) {
|
||||||
|
const rect = tweet.getBoundingClientRect();
|
||||||
|
const ratio = window.devicePixelRatio;
|
||||||
|
|
||||||
|
const parts = tweet.querySelector("time")?.closest("a")?.href?.split("/");
|
||||||
|
|
||||||
|
|
||||||
|
if (parts && parts.length > 5) {
|
||||||
|
const id = parts[5];
|
||||||
|
|
||||||
|
const by = {
|
||||||
|
name: tweet.querySelector("div[data-testid='User-Name'] a")?.innerText,
|
||||||
|
username: parts[3]
|
||||||
|
};
|
||||||
|
|
||||||
|
const me_data = document.querySelector("button[aria-label='Account menu']")?.innerText.split("\n");
|
||||||
|
|
||||||
|
|
||||||
|
const me = me_data && me_data.length > 1 ? {
|
||||||
|
name: me_data[0],
|
||||||
|
username: me_data[1]
|
||||||
|
}: undefined;
|
||||||
|
|
||||||
|
|
||||||
|
const is_private = tweet.querySelector("div[data-testid='User-Name'] svg[data-testid='icon-lock']") !== null;
|
||||||
|
|
||||||
|
chrome.runtime.sendMessage({ action: "like", rect, ratio, id, by, me, is_private });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// @TODO: unlike feature!
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const obs = new MutationObserver(obs_cb);
|
||||||
|
const config = {
|
||||||
|
subtree: true,
|
||||||
|
attributeFilter: ["data-testid"],
|
||||||
|
attributeOldValue: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
obs.observe(document, config);
|
||||||
27
ext/js/popup.js
Normal file
27
ext/js/popup.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
function resolve_field (type) {
|
||||||
|
return type === "checkbox" ? "checked" : "value";
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', async function () {
|
||||||
|
const names = ["token", "group", "header", "domain", "blacklist", /*"delay",*/ "posts", "likes", "private", "screenshot"];
|
||||||
|
const storage = await chrome.storage.local.get();
|
||||||
|
|
||||||
|
for (let i = 0; i < names.length; i++) {
|
||||||
|
const name = names[i];
|
||||||
|
const element = document.getElementById(name);
|
||||||
|
|
||||||
|
if (element) {
|
||||||
|
const field = resolve_field(element.type);
|
||||||
|
|
||||||
|
let saved = storage[name];
|
||||||
|
|
||||||
|
if (saved) {
|
||||||
|
element[field] = saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.addEventListener("change", async (evt) => {
|
||||||
|
await chrome.storage.local.set({ [name]: evt.target[field] });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
751
ext/js/wasm/wasm_mod.js
Normal file
751
ext/js/wasm/wasm_mod.js
Normal file
@ -0,0 +1,751 @@
|
|||||||
|
let wasm;
|
||||||
|
|
||||||
|
const heap = new Array(128).fill(undefined);
|
||||||
|
|
||||||
|
heap.push(undefined, null, true, false);
|
||||||
|
|
||||||
|
function getObject(idx) { return heap[idx]; }
|
||||||
|
|
||||||
|
function _assertBoolean(n) {
|
||||||
|
if (typeof(n) !== 'boolean') {
|
||||||
|
throw new Error(`expected a boolean argument, found ${typeof(n)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _assertNum(n) {
|
||||||
|
if (typeof(n) !== 'number') throw new Error(`expected a number argument, found ${typeof(n)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let WASM_VECTOR_LEN = 0;
|
||||||
|
|
||||||
|
let cachedUint8ArrayMemory0 = null;
|
||||||
|
|
||||||
|
function getUint8ArrayMemory0() {
|
||||||
|
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
||||||
|
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
||||||
|
}
|
||||||
|
return cachedUint8ArrayMemory0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
|
||||||
|
|
||||||
|
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
|
||||||
|
? function (arg, view) {
|
||||||
|
return cachedTextEncoder.encodeInto(arg, view);
|
||||||
|
}
|
||||||
|
: function (arg, view) {
|
||||||
|
const buf = cachedTextEncoder.encode(arg);
|
||||||
|
view.set(buf);
|
||||||
|
return {
|
||||||
|
read: arg.length,
|
||||||
|
written: buf.length
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function passStringToWasm0(arg, malloc, realloc) {
|
||||||
|
|
||||||
|
if (typeof(arg) !== 'string') throw new Error(`expected a string argument, found ${typeof(arg)}`);
|
||||||
|
|
||||||
|
if (realloc === undefined) {
|
||||||
|
const buf = cachedTextEncoder.encode(arg);
|
||||||
|
const ptr = malloc(buf.length, 1) >>> 0;
|
||||||
|
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
||||||
|
WASM_VECTOR_LEN = buf.length;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = arg.length;
|
||||||
|
let ptr = malloc(len, 1) >>> 0;
|
||||||
|
|
||||||
|
const mem = getUint8ArrayMemory0();
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
for (; offset < len; offset++) {
|
||||||
|
const code = arg.charCodeAt(offset);
|
||||||
|
if (code > 0x7F) break;
|
||||||
|
mem[ptr + offset] = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset !== len) {
|
||||||
|
if (offset !== 0) {
|
||||||
|
arg = arg.slice(offset);
|
||||||
|
}
|
||||||
|
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
||||||
|
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
||||||
|
const ret = encodeString(arg, view);
|
||||||
|
if (ret.read !== arg.length) throw new Error('failed to pass whole string');
|
||||||
|
offset += ret.written;
|
||||||
|
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WASM_VECTOR_LEN = offset;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLikeNone(x) {
|
||||||
|
return x === undefined || x === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cachedDataViewMemory0 = null;
|
||||||
|
|
||||||
|
function getDataViewMemory0() {
|
||||||
|
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
|
||||||
|
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
||||||
|
}
|
||||||
|
return cachedDataViewMemory0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
|
||||||
|
|
||||||
|
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
|
||||||
|
|
||||||
|
function getStringFromWasm0(ptr, len) {
|
||||||
|
ptr = ptr >>> 0;
|
||||||
|
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
||||||
|
}
|
||||||
|
|
||||||
|
let heap_next = heap.length;
|
||||||
|
|
||||||
|
function addHeapObject(obj) {
|
||||||
|
if (heap_next === heap.length) heap.push(heap.length + 1);
|
||||||
|
const idx = heap_next;
|
||||||
|
heap_next = heap[idx];
|
||||||
|
|
||||||
|
if (typeof(heap_next) !== 'number') throw new Error('corrupt heap');
|
||||||
|
|
||||||
|
heap[idx] = obj;
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dropObject(idx) {
|
||||||
|
if (idx < 132) return;
|
||||||
|
heap[idx] = heap_next;
|
||||||
|
heap_next = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
function takeObject(idx) {
|
||||||
|
const ret = getObject(idx);
|
||||||
|
dropObject(idx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function debugString(val) {
|
||||||
|
// primitive types
|
||||||
|
const type = typeof val;
|
||||||
|
if (type == 'number' || type == 'boolean' || val == null) {
|
||||||
|
return `${val}`;
|
||||||
|
}
|
||||||
|
if (type == 'string') {
|
||||||
|
return `"${val}"`;
|
||||||
|
}
|
||||||
|
if (type == 'symbol') {
|
||||||
|
const description = val.description;
|
||||||
|
if (description == null) {
|
||||||
|
return 'Symbol';
|
||||||
|
} else {
|
||||||
|
return `Symbol(${description})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type == 'function') {
|
||||||
|
const name = val.name;
|
||||||
|
if (typeof name == 'string' && name.length > 0) {
|
||||||
|
return `Function(${name})`;
|
||||||
|
} else {
|
||||||
|
return 'Function';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// objects
|
||||||
|
if (Array.isArray(val)) {
|
||||||
|
const length = val.length;
|
||||||
|
let debug = '[';
|
||||||
|
if (length > 0) {
|
||||||
|
debug += debugString(val[0]);
|
||||||
|
}
|
||||||
|
for(let i = 1; i < length; i++) {
|
||||||
|
debug += ', ' + debugString(val[i]);
|
||||||
|
}
|
||||||
|
debug += ']';
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
// Test for built-in
|
||||||
|
const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
|
||||||
|
let className;
|
||||||
|
if (builtInMatches.length > 1) {
|
||||||
|
className = builtInMatches[1];
|
||||||
|
} else {
|
||||||
|
// Failed to match the standard '[object ClassName]'
|
||||||
|
return toString.call(val);
|
||||||
|
}
|
||||||
|
if (className == 'Object') {
|
||||||
|
// we're a user defined class or Object
|
||||||
|
// JSON.stringify avoids problems with cycles, and is generally much
|
||||||
|
// easier than looping through ownProperties of `val`.
|
||||||
|
try {
|
||||||
|
return 'Object(' + JSON.stringify(val) + ')';
|
||||||
|
} catch (_) {
|
||||||
|
return 'Object';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// errors
|
||||||
|
if (val instanceof Error) {
|
||||||
|
return `${val.name}: ${val.message}\n${val.stack}`;
|
||||||
|
}
|
||||||
|
// TODO we could test for more things here, like `Set`s and `Map`s.
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined')
|
||||||
|
? { register: () => {}, unregister: () => {} }
|
||||||
|
: new FinalizationRegistry(state => {
|
||||||
|
wasm.__wbindgen_export_2.get(state.dtor)(state.a, state.b)
|
||||||
|
});
|
||||||
|
|
||||||
|
function makeMutClosure(arg0, arg1, dtor, f) {
|
||||||
|
const state = { a: arg0, b: arg1, cnt: 1, dtor };
|
||||||
|
const real = (...args) => {
|
||||||
|
// First up with a closure we increment the internal reference
|
||||||
|
// count. This ensures that the Rust closure environment won't
|
||||||
|
// be deallocated while we're invoking it.
|
||||||
|
state.cnt++;
|
||||||
|
const a = state.a;
|
||||||
|
state.a = 0;
|
||||||
|
try {
|
||||||
|
return f(a, state.b, ...args);
|
||||||
|
} finally {
|
||||||
|
if (--state.cnt === 0) {
|
||||||
|
wasm.__wbindgen_export_2.get(state.dtor)(a, state.b);
|
||||||
|
CLOSURE_DTORS.unregister(state);
|
||||||
|
} else {
|
||||||
|
state.a = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
real.original = state;
|
||||||
|
CLOSURE_DTORS.register(real, state, state);
|
||||||
|
return real;
|
||||||
|
}
|
||||||
|
|
||||||
|
function logError(f, args) {
|
||||||
|
try {
|
||||||
|
return f.apply(this, args);
|
||||||
|
} catch (e) {
|
||||||
|
let error = (function () {
|
||||||
|
try {
|
||||||
|
return e instanceof Error ? `${e.message}\n\nStack:\n${e.stack}` : e.toString();
|
||||||
|
} catch(_) {
|
||||||
|
return "<failed to stringify thrown value>";
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
console.error("wasm-bindgen: imported JS function that was not marked as `catch` threw an error:", error);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function __wbg_adapter_36(arg0, arg1, arg2) {
|
||||||
|
_assertNum(arg0);
|
||||||
|
_assertNum(arg1);
|
||||||
|
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h6ca29b9613afd685(arg0, arg1, addHeapObject(arg2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleError(f, args) {
|
||||||
|
try {
|
||||||
|
return f.apply(this, args);
|
||||||
|
} catch (e) {
|
||||||
|
wasm.__wbindgen_exn_store(addHeapObject(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {string} link
|
||||||
|
*/
|
||||||
|
export function post(link) {
|
||||||
|
const ptr0 = passStringToWasm0(link, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len0 = WASM_VECTOR_LEN;
|
||||||
|
wasm.post(ptr0, len0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function passArray8ToWasm0(arg, malloc) {
|
||||||
|
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
||||||
|
getUint8ArrayMemory0().set(arg, ptr / 1);
|
||||||
|
WASM_VECTOR_LEN = arg.length;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {any} tweet
|
||||||
|
* @param {Uint8Array | undefined} [image]
|
||||||
|
* @returns {Promise<number | undefined>}
|
||||||
|
*/
|
||||||
|
export function like(tweet, image) {
|
||||||
|
var ptr0 = isLikeNone(image) ? 0 : passArray8ToWasm0(image, wasm.__wbindgen_malloc);
|
||||||
|
var len0 = WASM_VECTOR_LEN;
|
||||||
|
const ret = wasm.like(addHeapObject(tweet), ptr0, len0);
|
||||||
|
return takeObject(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
function __wbg_adapter_123(arg0, arg1, arg2, arg3) {
|
||||||
|
_assertNum(arg0);
|
||||||
|
_assertNum(arg1);
|
||||||
|
wasm.wasm_bindgen__convert__closures__invoke2_mut__h8b3bb179cc2990bd(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function __wbg_load(module, imports) {
|
||||||
|
if (typeof Response === 'function' && module instanceof Response) {
|
||||||
|
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||||
|
try {
|
||||||
|
return await WebAssembly.instantiateStreaming(module, imports);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
if (module.headers.get('Content-Type') != 'application/wasm') {
|
||||||
|
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bytes = await module.arrayBuffer();
|
||||||
|
return await WebAssembly.instantiate(bytes, imports);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const instance = await WebAssembly.instantiate(module, imports);
|
||||||
|
|
||||||
|
if (instance instanceof WebAssembly.Instance) {
|
||||||
|
return { instance, module };
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function __wbg_get_imports() {
|
||||||
|
const imports = {};
|
||||||
|
imports.wbg = {};
|
||||||
|
imports.wbg.__wbg_get_36a92e2d56d3a556 = function() { return handleError(function (arg0) {
|
||||||
|
const ret = chrome.storage.local.get(getObject(arg0));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbindgen_is_undefined = function(arg0) {
|
||||||
|
const ret = getObject(arg0) === undefined;
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_in = function(arg0, arg1) {
|
||||||
|
const ret = getObject(arg0) in getObject(arg1);
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_boolean_get = function(arg0) {
|
||||||
|
const v = getObject(arg0);
|
||||||
|
const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
|
||||||
|
_assertNum(ret);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
|
||||||
|
const obj = getObject(arg1);
|
||||||
|
const ret = typeof(obj) === 'string' ? obj : undefined;
|
||||||
|
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
var len1 = WASM_VECTOR_LEN;
|
||||||
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
||||||
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_is_object = function(arg0) {
|
||||||
|
const val = getObject(arg0);
|
||||||
|
const ret = typeof(val) === 'object' && val !== null;
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_log_7e890cdad20ab0b3 = function() { return logError(function (arg0, arg1) {
|
||||||
|
console.log(getStringFromWasm0(arg0, arg1));
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
|
||||||
|
const ret = new Error(getStringFromWasm0(arg0, arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
|
||||||
|
const obj = getObject(arg1);
|
||||||
|
const ret = typeof(obj) === 'number' ? obj : undefined;
|
||||||
|
if (!isLikeNone(ret)) {
|
||||||
|
_assertNum(ret);
|
||||||
|
}
|
||||||
|
getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true);
|
||||||
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_number_new = function(arg0) {
|
||||||
|
const ret = arg0;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
|
||||||
|
const ret = getStringFromWasm0(arg0, arg1);
|
||||||
|
return addHeapObject(ret);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_jsval_loose_eq = function(arg0, arg1) {
|
||||||
|
const ret = getObject(arg0) == getObject(arg1);
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
|
||||||
|
const ret = getObject(arg0);
|
||||||
|
return addHeapObject(ret);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_getwithrefkey_edc2c8960f0f1191 = function() { return logError(function (arg0, arg1) {
|
||||||
|
const ret = getObject(arg0)[getObject(arg1)];
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_fetch_25e3a297f7b04639 = function() { return logError(function (arg0) {
|
||||||
|
const ret = fetch(getObject(arg0));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbindgen_is_function = function(arg0) {
|
||||||
|
const ret = typeof(getObject(arg0)) === 'function';
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_cb_drop = function(arg0) {
|
||||||
|
const obj = takeObject(arg0).original;
|
||||||
|
if (obj.cnt-- == 1) {
|
||||||
|
obj.a = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const ret = false;
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
imports.wbg.__wbg_queueMicrotask_12a30234db4045d3 = function() { return logError(function (arg0) {
|
||||||
|
queueMicrotask(getObject(arg0));
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_queueMicrotask_48421b3cc9052b68 = function() { return logError(function (arg0) {
|
||||||
|
const ret = getObject(arg0).queueMicrotask;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_signal_41e46ccad44bb5e2 = function() { return logError(function (arg0) {
|
||||||
|
const ret = getObject(arg0).signal;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_new_ebf2727385ee825c = function() { return handleError(function () {
|
||||||
|
const ret = new AbortController();
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_abort_8659d889a7877ae3 = function() { return logError(function (arg0) {
|
||||||
|
getObject(arg0).abort();
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_settype_b6ab7b74bd1908a1 = function() { return logError(function (arg0, arg1, arg2) {
|
||||||
|
getObject(arg0).type = getStringFromWasm0(arg1, arg2);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_newwithstrandinit_a31c69e4cc337183 = function() { return handleError(function (arg0, arg1, arg2) {
|
||||||
|
const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_setbody_734cb3d7ee8e6e96 = function() { return logError(function (arg0, arg1) {
|
||||||
|
getObject(arg0).body = getObject(arg1);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_setcredentials_2b67800db3f7b621 = function() { return logError(function (arg0, arg1) {
|
||||||
|
getObject(arg0).credentials = ["omit","same-origin","include",][arg1];
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_setheaders_be10a5ab566fd06f = function() { return logError(function (arg0, arg1) {
|
||||||
|
getObject(arg0).headers = getObject(arg1);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_setmethod_dc68a742c2db5c6a = function() { return logError(function (arg0, arg1, arg2) {
|
||||||
|
getObject(arg0).method = getStringFromWasm0(arg1, arg2);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_setmode_a781aae2bd3df202 = function() { return logError(function (arg0, arg1) {
|
||||||
|
getObject(arg0).mode = ["same-origin","no-cors","cors","navigate",][arg1];
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_setsignal_91c4e8ebd04eb935 = function() { return logError(function (arg0, arg1) {
|
||||||
|
getObject(arg0).signal = getObject(arg1);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_fetch_ba7fe179e527d942 = function() { return logError(function (arg0, arg1) {
|
||||||
|
const ret = getObject(arg0).fetch(getObject(arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_newwithu8arraysequenceandoptions_c8bc456a23f02fca = function() { return handleError(function (arg0, arg1) {
|
||||||
|
const ret = new Blob(getObject(arg0), getObject(arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_new_f9f1d655d855a601 = function() { return handleError(function () {
|
||||||
|
const ret = new FormData();
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_append_876bddfd2c8b42fb = function() { return handleError(function (arg0, arg1, arg2, arg3) {
|
||||||
|
getObject(arg0).append(getStringFromWasm0(arg1, arg2), getObject(arg3));
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_append_fc486ec9757bf1c1 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) {
|
||||||
|
getObject(arg0).append(getStringFromWasm0(arg1, arg2), getObject(arg3), getStringFromWasm0(arg4, arg5));
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_append_b10805b72af15312 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||||
|
getObject(arg0).append(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_new_e27c93803e1acc42 = function() { return handleError(function () {
|
||||||
|
const ret = new Headers();
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_append_f3a4426bb50622c5 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||||
|
getObject(arg0).append(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_instanceof_Response_e91b7eb7c611a9ae = function() { return logError(function (arg0) {
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
result = getObject(arg0) instanceof Response;
|
||||||
|
} catch (_) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
const ret = result;
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_url_1bf85c8abeb8c92d = function() { return logError(function (arg0, arg1) {
|
||||||
|
const ret = getObject(arg1).url;
|
||||||
|
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len1 = WASM_VECTOR_LEN;
|
||||||
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
||||||
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_status_ae8de515694c5c7c = function() { return logError(function (arg0) {
|
||||||
|
const ret = getObject(arg0).status;
|
||||||
|
_assertNum(ret);
|
||||||
|
return ret;
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_headers_5e283e8345689121 = function() { return logError(function (arg0) {
|
||||||
|
const ret = getObject(arg0).headers;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_new_a220cf903aa02ca2 = function() { return logError(function () {
|
||||||
|
const ret = new Array();
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_push_37c89022f34c01ca = function() { return logError(function (arg0, arg1) {
|
||||||
|
const ret = getObject(arg0).push(getObject(arg1));
|
||||||
|
_assertNum(ret);
|
||||||
|
return ret;
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_instanceof_ArrayBuffer_61dfc3198373c902 = function() { return logError(function (arg0) {
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
result = getObject(arg0) instanceof ArrayBuffer;
|
||||||
|
} catch (_) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
const ret = result;
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_new_796382978dfd4fb0 = function() { return logError(function (arg0, arg1) {
|
||||||
|
const ret = new Error(getStringFromWasm0(arg0, arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_newnoargs_76313bd6ff35d0f2 = function() { return logError(function (arg0, arg1) {
|
||||||
|
const ret = new Function(getStringFromWasm0(arg0, arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_call_1084a111329e68ce = function() { return handleError(function (arg0, arg1) {
|
||||||
|
const ret = getObject(arg0).call(getObject(arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_call_89af060b4e1523f2 = function() { return handleError(function (arg0, arg1, arg2) {
|
||||||
|
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_next_f9cb570345655b9a = function() { return handleError(function (arg0) {
|
||||||
|
const ret = getObject(arg0).next();
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_next_de3e9db4440638b2 = function() { return logError(function (arg0) {
|
||||||
|
const ret = getObject(arg0).next;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_done_bfda7aa8f252b39f = function() { return logError(function (arg0) {
|
||||||
|
const ret = getObject(arg0).done;
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_value_6d39332ab4788d86 = function() { return logError(function (arg0) {
|
||||||
|
const ret = getObject(arg0).value;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_new_525245e2b9901204 = function() { return logError(function () {
|
||||||
|
const ret = new Object();
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_iterator_888179a48810a9fe = function() { return logError(function () {
|
||||||
|
const ret = Symbol.iterator;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_new_b85e72ed1bfd57f9 = function() { return logError(function (arg0, arg1) {
|
||||||
|
try {
|
||||||
|
var state0 = {a: arg0, b: arg1};
|
||||||
|
var cb0 = (arg0, arg1) => {
|
||||||
|
const a = state0.a;
|
||||||
|
state0.a = 0;
|
||||||
|
try {
|
||||||
|
return __wbg_adapter_123(a, state0.b, arg0, arg1);
|
||||||
|
} finally {
|
||||||
|
state0.a = a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const ret = new Promise(cb0);
|
||||||
|
return addHeapObject(ret);
|
||||||
|
} finally {
|
||||||
|
state0.a = state0.b = 0;
|
||||||
|
}
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_resolve_570458cb99d56a43 = function() { return logError(function (arg0) {
|
||||||
|
const ret = Promise.resolve(getObject(arg0));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_then_95e6edc0f89b73b1 = function() { return logError(function (arg0, arg1) {
|
||||||
|
const ret = getObject(arg0).then(getObject(arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_then_876bb3c633745cc6 = function() { return logError(function (arg0, arg1, arg2) {
|
||||||
|
const ret = getObject(arg0).then(getObject(arg1), getObject(arg2));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_globalThis_86b222e13bdf32ed = function() { return handleError(function () {
|
||||||
|
const ret = globalThis.globalThis;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_self_3093d5d1f7bcb682 = function() { return handleError(function () {
|
||||||
|
const ret = self.self;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_window_3bcfc4d31bc012f8 = function() { return handleError(function () {
|
||||||
|
const ret = window.window;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_global_e5a3fe56f8be9485 = function() { return handleError(function () {
|
||||||
|
const ret = global.global;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_instanceof_Uint8Array_247a91427532499e = function() { return logError(function (arg0) {
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
result = getObject(arg0) instanceof Uint8Array;
|
||||||
|
} catch (_) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
const ret = result;
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_new_ea1883e1e5e86686 = function() { return logError(function (arg0) {
|
||||||
|
const ret = new Uint8Array(getObject(arg0));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_newwithbyteoffsetandlength_8a2cb9ca96b27ec9 = function() { return logError(function (arg0, arg1, arg2) {
|
||||||
|
const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_length_8339fcf5d8ecd12e = function() { return logError(function (arg0) {
|
||||||
|
const ret = getObject(arg0).length;
|
||||||
|
_assertNum(ret);
|
||||||
|
return ret;
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_set_d1e79e2388520f18 = function() { return logError(function (arg0, arg1, arg2) {
|
||||||
|
getObject(arg0).set(getObject(arg1), arg2 >>> 0);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_buffer_b7b08af79b0b0974 = function() { return logError(function (arg0) {
|
||||||
|
const ret = getObject(arg0).buffer;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_stringify_bbf45426c92a6bf5 = function() { return handleError(function (arg0) {
|
||||||
|
const ret = JSON.stringify(getObject(arg0));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_get_224d16597dbbfd96 = function() { return handleError(function (arg0, arg1) {
|
||||||
|
const ret = Reflect.get(getObject(arg0), getObject(arg1));
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbg_has_4bfbc01db38743f7 = function() { return handleError(function (arg0, arg1) {
|
||||||
|
const ret = Reflect.has(getObject(arg0), getObject(arg1));
|
||||||
|
_assertBoolean(ret);
|
||||||
|
return ret;
|
||||||
|
}, arguments) };
|
||||||
|
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
|
||||||
|
const ret = debugString(getObject(arg1));
|
||||||
|
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||||
|
const len1 = WASM_VECTOR_LEN;
|
||||||
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
||||||
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
|
||||||
|
takeObject(arg0);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
|
||||||
|
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_memory = function() {
|
||||||
|
const ret = wasm.memory;
|
||||||
|
return addHeapObject(ret);
|
||||||
|
};
|
||||||
|
imports.wbg.__wbindgen_closure_wrapper1265 = function() { return logError(function (arg0, arg1, arg2) {
|
||||||
|
const ret = makeMutClosure(arg0, arg1, 109, __wbg_adapter_36);
|
||||||
|
return addHeapObject(ret);
|
||||||
|
}, arguments) };
|
||||||
|
|
||||||
|
return imports;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __wbg_init_memory(imports, memory) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function __wbg_finalize_init(instance, module) {
|
||||||
|
wasm = instance.exports;
|
||||||
|
__wbg_init.__wbindgen_wasm_module = module;
|
||||||
|
cachedDataViewMemory0 = null;
|
||||||
|
cachedUint8ArrayMemory0 = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return wasm;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSync(module) {
|
||||||
|
if (wasm !== undefined) return wasm;
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof module !== 'undefined' && Object.getPrototypeOf(module) === Object.prototype)
|
||||||
|
({module} = module)
|
||||||
|
else
|
||||||
|
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
|
||||||
|
|
||||||
|
const imports = __wbg_get_imports();
|
||||||
|
|
||||||
|
__wbg_init_memory(imports);
|
||||||
|
|
||||||
|
if (!(module instanceof WebAssembly.Module)) {
|
||||||
|
module = new WebAssembly.Module(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = new WebAssembly.Instance(module, imports);
|
||||||
|
|
||||||
|
return __wbg_finalize_init(instance, module);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function __wbg_init(module_or_path) {
|
||||||
|
if (wasm !== undefined) return wasm;
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype)
|
||||||
|
({module_or_path} = module_or_path)
|
||||||
|
else
|
||||||
|
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
|
||||||
|
|
||||||
|
if (typeof module_or_path === 'undefined') {
|
||||||
|
module_or_path = new URL('wasm_mod_bg.wasm', import.meta.url);
|
||||||
|
}
|
||||||
|
const imports = __wbg_get_imports();
|
||||||
|
|
||||||
|
if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
|
||||||
|
module_or_path = fetch(module_or_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
__wbg_init_memory(imports);
|
||||||
|
|
||||||
|
const { instance, module } = await __wbg_load(await module_or_path, imports);
|
||||||
|
|
||||||
|
return __wbg_finalize_init(instance, module);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { initSync };
|
||||||
|
export default __wbg_init;
|
||||||
BIN
ext/js/wasm/wasm_mod_bg.wasm
Normal file
BIN
ext/js/wasm/wasm_mod_bg.wasm
Normal file
Binary file not shown.
58
ext/manifest_cr.json
Normal file
58
ext/manifest_cr.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 3,
|
||||||
|
"name": "Teletweet",
|
||||||
|
"short_name": "Teletweet",
|
||||||
|
"description": "Post your likes from Twitter (\"\"\"X\"\"\") to your Telegram channel",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"author": "@yk",
|
||||||
|
"minimum_chrome_version": "110",
|
||||||
|
"offline_enabled": false,
|
||||||
|
"action": {
|
||||||
|
"default_title": "Posts a like",
|
||||||
|
"default_icon": {
|
||||||
|
"16": "assets/icon16.png",
|
||||||
|
"32": "assets/icon32.png",
|
||||||
|
"48": "assets/icon48.png",
|
||||||
|
"128": "assets/icon128.png"
|
||||||
|
},
|
||||||
|
"default_popup": "popup.html",
|
||||||
|
"show_matches": [
|
||||||
|
"*://x.com/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"content_security_policy": {
|
||||||
|
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"type": "module",
|
||||||
|
"service_worker": "js/background.js"
|
||||||
|
},
|
||||||
|
"permissions": [
|
||||||
|
"webRequest",
|
||||||
|
"storage",
|
||||||
|
"activeTab",
|
||||||
|
"offscreen"
|
||||||
|
],
|
||||||
|
"host_permissions": [
|
||||||
|
"*://*.x.com/*",
|
||||||
|
"<all_urls>"
|
||||||
|
],
|
||||||
|
"web_accessible_resources": [
|
||||||
|
{
|
||||||
|
"matches": [
|
||||||
|
"<all_urls>"
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
"js/wasm/wasm_mod.js",
|
||||||
|
"js/wasm/wasm_mod_bg.wasm"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"content_scripts": [
|
||||||
|
{
|
||||||
|
"matches": ["https://*.x.com/*"],
|
||||||
|
"js": ["js/content-script.js"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
58
ext/manifest_ff.json
Normal file
58
ext/manifest_ff.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 3,
|
||||||
|
"name": "Teletweet",
|
||||||
|
"short_name": "Teletweet",
|
||||||
|
"description": "Post your likes from Twitter (\"\"\"X\"\"\") to your Telegram channel",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"author": "@yk",
|
||||||
|
"action": {
|
||||||
|
"default_title": "Posts a like",
|
||||||
|
"default_icon": {
|
||||||
|
"16": "assets/icon16.png",
|
||||||
|
"32": "assets/icon32.png",
|
||||||
|
"48": "assets/icon48.png",
|
||||||
|
"128": "assets/icon128.png"
|
||||||
|
},
|
||||||
|
"default_popup": "popup.html"
|
||||||
|
},
|
||||||
|
"content_security_policy": {
|
||||||
|
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"type": "module",
|
||||||
|
"scripts": ["js/background.js"]
|
||||||
|
},
|
||||||
|
"permissions": [
|
||||||
|
"webRequest",
|
||||||
|
"storage",
|
||||||
|
"activeTab",
|
||||||
|
"offscreen"
|
||||||
|
],
|
||||||
|
"host_permissions": [
|
||||||
|
"*://*.x.com/*",
|
||||||
|
"<all_urls>"
|
||||||
|
],
|
||||||
|
"web_accessible_resources": [
|
||||||
|
{
|
||||||
|
"matches": [
|
||||||
|
"<all_urls>"
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
"js/wasm/wasm_mod.js",
|
||||||
|
"js/wasm/wasm_mod_bg.wasm"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"browser_specific_settings": {
|
||||||
|
"gecko": {
|
||||||
|
"id": "{aed20410-8c19-4833-aa70-42223e29c364}",
|
||||||
|
"strict_min_version": "112.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"content_scripts": [
|
||||||
|
{
|
||||||
|
"matches": ["https://*.x.com/*"],
|
||||||
|
"js": ["js/content-script.js"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
273
ext/popup.html
Normal file
273
ext/popup.html
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<script type="module" src="js/popup.js"> </script>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inner";
|
||||||
|
src:
|
||||||
|
local("Inner Tight"),
|
||||||
|
url("assets/InterTight-VariableFont_wght.ttf") format("truetype"),
|
||||||
|
url("assets/InterTight-Italic-VariableFont_wght.ttf") format("truetype"),
|
||||||
|
url("assets/static/InterTight-Medium.ttf") format("truetype")
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, section, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, ::placeholder {
|
||||||
|
font-family: "Inner", sans-serif;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Inner", sans-serif;
|
||||||
|
background-color:#000;
|
||||||
|
background-image:
|
||||||
|
radial-gradient(at 76% 92%, hsla(215,53%,18%,1) 0px, transparent 50%),
|
||||||
|
radial-gradient(at 35% 70%, hsla(176,53%,18%,1) 0px, transparent 50%),
|
||||||
|
radial-gradient(at 73% 70%, hsla(72,53%,18%,1) 0px, transparent 50%),
|
||||||
|
radial-gradient(at 22% 82%, hsla(203,53%,18%,1) 0px, transparent 50%),
|
||||||
|
radial-gradient(at 14% 36%, hsla(229,53%,18%,1) 0px, transparent 50%),
|
||||||
|
radial-gradient(at 19% 58%, hsla(112,53%,18%,1) 0px, transparent 50%);
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
margin: 10px;
|
||||||
|
padding: 15px;
|
||||||
|
background: rgba(0, 0, 0, .88);
|
||||||
|
border-radius: 2px;
|
||||||
|
min-width: 600px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
a, a:visited {
|
||||||
|
color: rgba(220, 220, 230, 1);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: rgba(255, 255, 255, 1);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app > section {
|
||||||
|
width: 49%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app > section > span {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-size: 0.77em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
input[type=text], input[type=number] {
|
||||||
|
height: 24px;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 2px 10px;
|
||||||
|
background: rgba(244, 244, 244, .85);
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
input[type=checkbox] {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
width: 100%;
|
||||||
|
text-transform: lowercase;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#app > section:nth-child(odd) {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app > * {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
section > h4 {
|
||||||
|
font-size: .667em;
|
||||||
|
margin-top: 11px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: 555;
|
||||||
|
}
|
||||||
|
|
||||||
|
section > h5 {
|
||||||
|
font-size: .50em;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: 300;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app > section:nth-child(odd) > h5 {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls h3 {
|
||||||
|
font-size: .667em;
|
||||||
|
font-weight: 555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-section {
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 49.5%;
|
||||||
|
}
|
||||||
|
.control-section:first-of-type {
|
||||||
|
border-right: solid 1px rgba(255, 255, 255, .887);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-section:first-of-type h3 {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-section:last-of-type section {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-section span {
|
||||||
|
font-size: .54em;
|
||||||
|
display: block;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-section section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
font-size: 0.77em;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<h2>↓ Texho</h2>
|
||||||
|
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h4>Токен бота</h4>
|
||||||
|
<h5>(брать здесь: <a target="_blank" href="https://t.me/BotFather">t.me/BotFather</a>)</h5>
|
||||||
|
<input type="text" id="token" placeholder="your telegram bot token">
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h4>ID группы/чата</h4>
|
||||||
|
<h5>(ID каналов и групп начинаются с -100)</h5>
|
||||||
|
<input type="text" id="group" placeholder="your group/channel id">
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h4>Кастомный домен</h4>
|
||||||
|
<h5>(дефолт — x.com, можно использовать зеркала с пофикшенными превью, типа fixupx.com (никаких гарантий)</h5>
|
||||||
|
<input type="text" id="domain" placeholder="domain">
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h4>Заголовок</h4>
|
||||||
|
<h5>Будет отображаться перед ссылкой на твит. Можно использовать теги {me} и {notme}.</h5>
|
||||||
|
<input type="text" id="header" placeholder="your custom header message">
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h4>Фильтр пользователей</h4>
|
||||||
|
<h5>(без @, через запятую, лайки аккаунтам с юзернеймами из списка не будут отправлены боту)</h5>
|
||||||
|
<input type="text" id="blacklist" placeholder="(ex.: elonmusk,elonmusksmom,elonmusksgrandmother,elonmusksdad,elonmusksdog)">
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- <section> -->
|
||||||
|
<!-- <h4>Задержка для скриншота</h4> -->
|
||||||
|
<!-- <h5>(если включена функция скриншота; мс; 0-300; дефолт 0)</h5> -->
|
||||||
|
<!-- <input type="number" id="delay" min="0" max="300" placeholder="delay"> -->
|
||||||
|
<!-- </section> -->
|
||||||
|
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<div class="control-section">
|
||||||
|
<h3>Посты</h3>
|
||||||
|
<section><input type="checkbox" id="posts"><span>Включить</span></section>
|
||||||
|
</div>
|
||||||
|
<div class="control-section">
|
||||||
|
<h3>Лайки</h3>
|
||||||
|
<section><input type="checkbox" id="likes"><span>Включить</span></section>
|
||||||
|
<section><input type="checkbox" id="private"><span>Включая закрытки</span></section>
|
||||||
|
<section><input type="checkbox" id="screenshot"><span>Делать скриншот (experimental)</span></section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>// <a target="_blank" href="https://t.me/fedpostltd">yk</a> (<a target="_blank" href="https://x.com/ymkeller">x/twitter</a>)</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
firefox.zip
Normal file
BIN
firefox.zip
Normal file
Binary file not shown.
1443
rs/Cargo.lock
generated
Normal file
1443
rs/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
48
rs/Cargo.toml
Normal file
48
rs/Cargo.toml
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
[package]
|
||||||
|
name = "extgk"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
js-sys = "0.3.70"
|
||||||
|
wasm-bindgen = "0.2.93"
|
||||||
|
wasm-bindgen-futures = "0.4"
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde-wasm-bindgen = "0.6"
|
||||||
|
urlencoding = "2.1"
|
||||||
|
|
||||||
|
# rand only works for WASM if JS support is enabled in a dependency
|
||||||
|
# See https://docs.rs/getrandom/latest/getrandom/#webassembly-support
|
||||||
|
rand = "0.8"
|
||||||
|
getrandom = { version = "0.2", features = ["js"] }
|
||||||
|
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||||
|
# logging them with `console.error`. This is great for development, but requires
|
||||||
|
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||||
|
# code size when deploying.
|
||||||
|
console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||||
|
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
|
||||||
|
# compared to the default allocator's ~10K. It is slower than the default
|
||||||
|
# allocator, however.
|
||||||
|
wee_alloc = { version = "0.4.5", optional = true }
|
||||||
|
reqwest = { version = "0.12.7", features = ["multipart"] }
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
version = "0.3.70"
|
||||||
|
features = [
|
||||||
|
"console",
|
||||||
|
"Blob",
|
||||||
|
"WorkerGlobalScope",
|
||||||
|
"Window",
|
||||||
|
"KeyEvent",
|
||||||
|
"Event",
|
||||||
|
'Headers',
|
||||||
|
'Request',
|
||||||
|
'RequestInit',
|
||||||
|
'RequestMode',
|
||||||
|
'Response',
|
||||||
|
'Storage',
|
||||||
|
]
|
||||||
198
rs/src/lib.rs
Normal file
198
rs/src/lib.rs
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
#![feature(let_chains)]
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use serde::{ Deserialize, Serialize };
|
||||||
|
use serde_json::json;
|
||||||
|
use wasm_bindgen::{ prelude::wasm_bindgen, JsValue };
|
||||||
|
|
||||||
|
use reqwest::{ Client, Url, multipart };
|
||||||
|
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
#[wasm_bindgen(js_namespace=console)]
|
||||||
|
fn log (s: &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
#[wasm_bindgen(catch, js_namespace = ["chrome", "storage", "local"], js_name = set)]
|
||||||
|
async fn storage_set (data: &JsValue) -> Result<JsValue, JsValue>;
|
||||||
|
|
||||||
|
#[wasm_bindgen(catch, js_namespace = ["chrome", "storage", "local"], js_name = get)]
|
||||||
|
async fn storage_get (data: &JsValue) -> Result<JsValue, JsValue>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn post (link: &str) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct LocalStorage {
|
||||||
|
pub token: String,
|
||||||
|
pub group: String,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub header: String,
|
||||||
|
#[serde(default = "default_domain")]
|
||||||
|
pub domain: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub blacklist: String,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
|
pub delay: u8,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub posts: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub likes: bool,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub private: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub screenshot: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct LikedTweet {
|
||||||
|
pub id: String,
|
||||||
|
pub by: TwitterUser,
|
||||||
|
pub me: Option<TwitterUser>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub is_private: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct TwitterUser {
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub username: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TwitterUser {
|
||||||
|
fn format (&self) -> String {
|
||||||
|
match &self.name {
|
||||||
|
Some(name) => format!("{name} ({})", self.username.trim_start_matches("@")),
|
||||||
|
None => format!("{}", self.username)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_domain () -> String {
|
||||||
|
String::from("x.com")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub fn escape (mut line: String) -> String {
|
||||||
|
const chars: [char; 21] = [ '\\', '_', '*', '[', ']', '(', ')', '~', '`', '>', '<', '&', '#', '+', '-', '=', '|', '{', '}', '.', '!' ];
|
||||||
|
for char in chars {
|
||||||
|
line = line.replace(char, &format!("\\{}", char));
|
||||||
|
}
|
||||||
|
line
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_telegram_api_url (token: &str) -> String {
|
||||||
|
format!("https://api.telegram.org/bot{token}")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_tweet_url (domain: &str, username: &str, id: &str) -> String {
|
||||||
|
format!("https://{domain}/{username}/status/{id}")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_caption (url: &str, header: &str, by: &TwitterUser, me: &Option<TwitterUser>) -> String {
|
||||||
|
let by = by.format();
|
||||||
|
let me = me.as_ref().map(TwitterUser::format);
|
||||||
|
|
||||||
|
// @TODO: Edge case of where header is set but we can't retrieve Me
|
||||||
|
|
||||||
|
let header = escape(header
|
||||||
|
.replace("{me}", &me.unwrap_or_default())
|
||||||
|
.replace("{notme}", &by));
|
||||||
|
|
||||||
|
format!("{}{header}{}{}",
|
||||||
|
if !header.is_empty() { "`" } else { Default::default() },
|
||||||
|
if !header.is_empty() { "`\r\n\r\n" } else { Default::default() },
|
||||||
|
escape(url.to_owned())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! log {
|
||||||
|
($data: expr) => {
|
||||||
|
log(&format!("{:?}", $data))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub async fn like (tweet: JsValue, image: Option<Vec<u8>>) -> Option<u8> {
|
||||||
|
let store = storage_get(&JsValue::null()).await.ok()?;
|
||||||
|
let store: LocalStorage = serde_wasm_bindgen::from_value(store).ok()?;
|
||||||
|
|
||||||
|
if !store.likes { return None; }
|
||||||
|
|
||||||
|
let blacklist = store.blacklist.split(",").map(str::trim).collect::<HashSet<&str>>();
|
||||||
|
|
||||||
|
let tweet: LikedTweet = serde_wasm_bindgen::from_value(tweet).ok()?;
|
||||||
|
|
||||||
|
if !store.private && tweet.is_private { return None; }
|
||||||
|
if blacklist.contains(tweet.by.username.as_str()) { return None; }
|
||||||
|
|
||||||
|
let domain = if store.domain.is_empty() { default_domain() } else { store.domain };
|
||||||
|
let group = store.group;
|
||||||
|
let token = store.token;
|
||||||
|
let url = format_tweet_url(&domain, &tweet.by.username, &tweet.id);
|
||||||
|
|
||||||
|
let caption = format_caption(&url, &store.header, &tweet.by, &tweet.me);
|
||||||
|
|
||||||
|
let client = Client::new();
|
||||||
|
|
||||||
|
let link_preview_options = json!({
|
||||||
|
"is_disabled": false,
|
||||||
|
"url": url,
|
||||||
|
"prefer_large_media": true,
|
||||||
|
"show_above_text": false,
|
||||||
|
}).to_string();
|
||||||
|
|
||||||
|
let (form, endpoint) = if let Some(image) = image && store.screenshot {
|
||||||
|
let endpoint = format!("{}/sendPhoto", format_telegram_api_url(&token));
|
||||||
|
let part = multipart::Part::bytes(image).file_name("test.png").mime_str("image/png").ok()?;
|
||||||
|
|
||||||
|
|
||||||
|
(reqwest::multipart::Form::new()
|
||||||
|
.text("chat_id", group)
|
||||||
|
.text("caption", caption)
|
||||||
|
.text("parse_mode", "MarkdownV2")
|
||||||
|
.text("link_preview_options", link_preview_options)
|
||||||
|
.part("photo", part),
|
||||||
|
endpoint)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
let endpoint = format!("{}/sendMessage", format_telegram_api_url(&token));
|
||||||
|
|
||||||
|
(reqwest::multipart::Form::new()
|
||||||
|
.text("chat_id", group)
|
||||||
|
.text("link_preview_options", link_preview_options)
|
||||||
|
.text("parse_mode", "MarkdownV2")
|
||||||
|
.text("text", caption),
|
||||||
|
endpoint)
|
||||||
|
};
|
||||||
|
|
||||||
|
let endpoint = Url::parse(&endpoint).ok()?;
|
||||||
|
let _resp = client
|
||||||
|
.post(endpoint)
|
||||||
|
.multipart(form)
|
||||||
|
.send().await.ok()?;
|
||||||
|
|
||||||
|
log!(_resp);
|
||||||
|
|
||||||
|
Some(0)
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user