feat: add scripts

This commit is contained in:
2023-08-22 01:28:47 +07:00
parent 7fe79a2bdb
commit 92c0e0ee6c
19 changed files with 581 additions and 438 deletions

8
web/aov-vn/README.md Normal file
View File

@ -0,0 +1,8 @@
# Scripts for Arena of Valor minigame
Scripts I created for this game, thats it. (Not cheating scripts in-game tho)
## Scripts
- [awc_autospin.js](./awc_autospin.js) - Auto spin the wheel in AWC website (Works in Vietnamese AOV only, other region need to tweak some string into their language)
- [apl2022-clicker.js](./apl2022-clicker.js) - "Auto click" to claim gift by abusing GraphQL requests.

View File

@ -0,0 +1,139 @@
if (!window.location.href.startsWith("https://apl2022.lienquan.garena.vn")) {
console.error("This script is for https://apl2022.lienquan.garena.vn only.");
}
async function getCurrentUser() {
const rsp = await fetch("/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
operationName: "getUser",
query: `
query getUser {
getUser {
id
name
icon
profile {
id
...Profile
__typename
}
__typename
}
}
fragment Profile on Profile {
tcid
clicks
totalClicks
dailyClicks
claimedGift
currentGift
receivedServerGift
subMissions
claimedDailyGift
date
item {
id
name
type
image
limitation
currentClaimed
__typename
}
sentWish
__typename
}
`,
variables: {},
}),
});
if (!rsp.ok) {
throw `Failed to get current user info`;
}
return (await rsp.json()).data.getUser;
}
async function postClick(amount) {
const rsp = await fetch("/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
operationName: "doDailyClick",
query: `
mutation doDailyClick($clicks: Int!) {
dailyClick(clicks: $clicks) {
id
...Profile
__typename
}
}
fragment Profile on Profile {
tcid
clicks
totalClicks
dailyClicks
claimedGift
currentGift
receivedServerGift
subMissions
claimedDailyGift
date
item {
id
name
type
image
limitation
currentClaimed
__typename
}
sentWish
__typename
}
`,
variables: {
clicks: amount,
},
}),
});
if (!rsp.ok) {
throw `Failed to post click request with amount ${amount}`;
}
}
async function main() {
console.log("Fetching user information...");
let user;
try {
user = await getCurrentUser();
} catch (e) {
console.error(e);
return;
}
console.log(`Hello, ${user.name}!`);
console.log("Calculating remaining clicks needed...");
const clicksNeeded = 1000 - user.profile.dailyClicks;
if (clicksNeeded == 0) {
console.warn("You've already clicked enough for a day :D");
return;
}
console.log(`Clicks needed: ${clicksNeeded}`);
console.log("Sending click request...");
try {
postClick(clicksNeeded);
} catch (e) {
console.error(e);
return;
}
console.log("Success! Please reload page to see the changes.");
}
main();

130
web/aov-vn/awc_autospin.js Normal file
View File

@ -0,0 +1,130 @@
// Fetch jQuery
await fetch("https://code.jquery.com/jquery-3.6.0.min.js")
.then((x) => x.text())
.then((y) => eval(y));
// Wait for jQuery to be loaded.
{
// From https://stackoverflow.com/a/53914092
class ClassWatcher {
constructor(
targetNode,
classToWatch,
classAddedCallback,
classRemovedCallback,
) {
this.targetNode = targetNode;
this.classToWatch = classToWatch;
this.classAddedCallback = classAddedCallback;
this.classRemovedCallback = classRemovedCallback;
this.observer = null;
this.lastClassState = targetNode.classList.contains(this.classToWatch);
this.init();
}
init() {
this.observer = new MutationObserver(this.mutationCallback);
this.observe();
}
observe() {
this.observer.observe(this.targetNode, { attributes: true });
}
disconnect() {
this.observer.disconnect();
}
mutationCallback = (mutationsList) => {
for (let mutation of mutationsList) {
if (
mutation.type === "attributes" &&
mutation.attributeName === "class"
) {
let currentClassState = mutation.target.classList.contains(
this.classToWatch,
);
if (this.lastClassState !== currentClassState) {
this.lastClassState = currentClassState;
if (currentClassState) {
this.classAddedCallback();
} else {
this.classRemovedCallback();
}
}
}
}
};
}
var disableChest = false;
function clickFirstButtonByClassName(className) {
let btn = document.getElementsByClassName(className)[0];
if (!(typeof btn === "undefined")) {
btn.dispatchEvent(new MouseEvent("click"));
}
}
// Click the spin button
function spin() {
clickFirstButtonByClassName("wheel__main--note");
if (!disableChest) {
clickFirstButtonByClassName("chest");
}
}
function pickCard() {
let teams = document.getElementsByClassName("popup-draw__card");
for (let i = 0; i < 3; i++) {
teams[i].dispatchEvent(new MouseEvent("click"));
}
setTimeout(() => jQuery(".ReactModal__Overlay").trigger("click"), 2000);
}
// Check for dialog message then close
function closeSwalDialog() {
clickFirstButtonByClassName("swal2-close");
if (document.getElementsByClassName("swal2-close").length > 0) {
setTimeout(closeSwalDialog, 100);
}
}
function Swal2Dialog() {
if (document.getElementsByClassName("popup-draw__card").length > 0) {
pickCard();
} else {
let swal2msg = document.getElementsByClassName("popup-alert__message");
if (swal2msg.length > 0) {
console.log(swal2msg[0].innerHTML);
if (
swal2msg[0].innerHTML ==
"Đã đạt đến giới hạn Rương đếm ngược hàng ngày"
) {
disableChest = true;
} else if (swal2msg[0].innerHTML == "Bạn đã hết lượt quay trong ngày") {
closeAutoFarm();
}
}
}
closeSwalDialog();
}
// Watch for SweetAlert 2
let swal2Watcher = new ClassWatcher(
document.body,
"swal2-shown",
Swal2Dialog,
spin,
);
function closeAutoFarm() {
swal2Watcher.disconnect();
}
spin();
// Disable window change
jQuery("window").off("mouseup");
jQuery("document").off("visibilitychange");
// Remove video player (so it isnt annoying to me and save CPU by a lot)
Array.from(document.getElementsByTagName("iframe")).forEach((iframe) => {
iframe.remove();
});
}

View File

@ -0,0 +1,52 @@
// Dependencies
eval(
await (
await fetch("https://html2canvas.hertzen.com/dist/html2canvas.min.js")
).text(),
);
eval(
await (
await fetch("https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js")
).text(),
);
eval(
await (
await fetch(
"https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.0/FileSaver.min.js",
)
).text(),
);
const zipFile = new JSZip();
async function screenshotAnswer(answerElement) {
console.log(answerElement);
const canvas = await html2canvas(answerElement);
return await new Promise((resolve) => canvas.toBlob(resolve));
}
async function saveImage(image, imageName) {
zipFile.file(imageName, image);
}
async function saveZip() {
const generatedFile = await zipFile.generateAsync({ type: "blob" });
console.log(`URL: ${URL.createObjectURL(generatedFile)}`);
saveAs(generatedFile, "olm-answers.zip");
}
const questionBtns = document.querySelector("#question-static").children;
const wrongQuestionCount =
document.querySelectorAll(".q-static.q-wrong").length;
for (const [index, questionBtn] of Array.from(questionBtns).entries()) {
if (index > questionBtns.length - 1 - wrongQuestionCount) {
break;
}
// Click the button
questionBtn.click();
const answerElement =
document.querySelector("#qholder").parentElement.parentElement;
const answerImage = await screenshotAnswer(answerElement);
saveImage(answerImage, `question-${index + 1}.png`);
}
await saveZip();