feat: add scripts
This commit is contained in:
8
web/aov-vn/README.md
Normal file
8
web/aov-vn/README.md
Normal 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.
|
||||
139
web/aov-vn/apl2022-clicker.js
Normal file
139
web/aov-vn/apl2022-clicker.js
Normal 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
130
web/aov-vn/awc_autospin.js
Normal 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();
|
||||
});
|
||||
}
|
||||
52
web/olm.vn/screenshot-answers.js
Normal file
52
web/olm.vn/screenshot-answers.js
Normal 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();
|
||||
Reference in New Issue
Block a user