feat: add scripts

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

View File

@ -1,45 +1,64 @@
# Lutris scripts
## `preloader.sh`
Execute multiple scripts in a folder (default is `./preloader`), usually useful for Lutris Pre-launch/Post-exit script
+ Logging is enabled by default, but can be disabled by changing DEBUG to 0 in script source (`DEBUG=0`)
> This script will execute scripts in **current working directory** *(where `preloader.sh` is executed)*, so for example if a script need a file called `nightmare`, and preloader.sh is in `~`, **put the file in `~`** *instead of `~/preloader/`*
- Logging is enabled by default, but can be disabled by changing DEBUG to 0 in script source (`DEBUG=0`)
> This script will execute scripts in **current working directory** _(where `preloader.sh` is executed)_, so for example if a script need a file called `nightmare`, and preloader.sh is in `~`, **put the file in `~`** _instead of `~/preloader/`_
### Installation
+ To download `preloader.sh` itself:
- To download `preloader.sh` itself:
```sh
curl -OL https://gitlab.com/tretrauit/scripts/-/raw/main/apps/Lutris/preloader.sh
chmod +x preloader.sh
```
+ After that, copy/move this script to the game prefix you want to use, then in Lutris:
- Set pre-launch script in Lutris to where `preloader.sh` is located.
- Disable **Wait for pre-launch script completion** (optional)
+ **IMPORTANT**: Now, to add pre-launch script, instead of setting them in Lutris, add them to `./preloader` (or the folder you specified).
+ Enjoy :L
- After that, copy/move this script to the game prefix you want to use, then in Lutris:
- Set pre-launch script in Lutris to where `preloader.sh` is located.
- Disable **Wait for pre-launch script completion** (optional)
- **IMPORTANT**: Now, to add pre-launch script, instead of setting them in Lutris, add them to `./preloader` (or the folder you specified).
- Enjoy :L
### Documentation
There are environment variables to control how preloader.sh work:
+ `PRELOADER_PATH=./preloader`: Path to preload scripts.
+ `PRELOADER_DEBUG=0`: Enable debug (1) or disable it (0)
- `PRELOADER_PATH=./preloader`: Path to preload scripts.
- `PRELOADER_DEBUG=0`: Enable debug (1) or disable it (0)
## `discord_rpc.sh`
Launch `winediscordrpcbridge.exe`, to be able to get Discord Rich Presence on Wine applications on the specified prefix.
### Installation
+ To install you must have [`winediscordrpcbridge.exe`](https://github.com/0e4ef622/wine-discord-ipc-bridge/) present, if not you can download latest version by executing
- To install you must have [`winediscordrpcbridge.exe`](https://github.com/0e4ef622/wine-discord-ipc-bridge/) present, if not you can download latest version by executing
```sh
curl -OL https://github.com/0e4ef622/wine-discord-ipc-bridge/releases/latest/download/winediscordipcbridge.exe
```
or use my build (latest commit: `master/9d56418`)
```sh
curl -OL https://github.com/teppyboy/releases/releases/download/git%2B0e4ef622%2Fwine-discord-ipc-bridge%2Bmaster%2F9d56418/winediscordipcbridge.exe
```
+ Then to download `discord_rpc.sh` itself:
- Then to download `discord_rpc.sh` itself:
```sh
curl -OL https://gitlab.com/tretrauit/scripts/-/raw/main/apps/Lutris/discord_rpc.sh
chmod +x discord_rpc.sh
```
+ After that, copy/move this script to the game prefix you want to use, then in Lutris:
- Set pre-launch script in Lutris to where `discord_rpc.sh` is located.
- Disable **Wait for pre-launch script completion**
+ Enjoy :L
- After that, copy/move this script to the game prefix you want to use, then in Lutris:
- Set pre-launch script in Lutris to where `discord_rpc.sh` is located.
- Disable **Wait for pre-launch script completion**
- Enjoy :L

View File

@ -4,19 +4,19 @@
### Notes
+ **YOU NEED TO HAVE WS-SCRCPY INSTALLED, ALONG WITH ROOT ACCESS AND DEPENDENCIES**
+ ~~YOU ALSO NEED TO OPEN ADB WIRELESS IN DEVELOPER SETTINGS FOR THIS TO WORK~~ (The script can use `su` to start ADB wireless now)
+ You need to grant Termux:API full Location permission and set to "Always" (Foreground mode will not work correctly)
+ Rootless mode is available, although it **will not** work in most cases.
+ Dependencies: `root-repo` `tsu` `moreutils` `build-essential` `nodejs` `python3` `android-tools` `git` `termux-api`
- **YOU NEED TO HAVE WS-SCRCPY INSTALLED, ALONG WITH ROOT ACCESS AND DEPENDENCIES**
- ~~YOU ALSO NEED TO OPEN ADB WIRELESS IN DEVELOPER SETTINGS FOR THIS TO WORK~~ (The script can use `su` to start ADB wireless now)
- You need to grant Termux:API full Location permission and set to "Always" (Foreground mode will not work correctly)
- Rootless mode is available, although it **will not** work in most cases.
- Dependencies: `root-repo` `tsu` `moreutils` `build-essential` `nodejs` `python3` `android-tools` `git` `termux-api`
> Or execute `pkg install root-repo tsu moreutils build-essential nodejs python3 android-tools git termux-api`
+ You also need to downgrade npm to version 6 to fix Termux problem: `npm install -g npm@6`
- You also need to downgrade npm to version 6 to fix Termux problem: `npm install -g npm@6`
> Please ignore the vulnerability message, if you care about it then please don't use this script.
+ Download ws-scrcpy-launcher.py:
- Download ws-scrcpy-launcher.py:
```bash
curl -OL https://gitlab.com/tretrauit/scripts/-/raw/main/Apps/ws-scrcpy/ws-scrcpy-launcher.py
@ -25,7 +25,7 @@ chmod +x ws-scrcpy-launcher.py
> Execute `./ws-scrcpy-launcher.py` to launch ws-scrcpy with scrcpy server for local device.
+ Full script for lazy people (including install ws-scrcpy steps):
- Full script for lazy people (including install ws-scrcpy steps):
```bash
pkg update
@ -41,6 +41,6 @@ curl -OL https://gitlab.com/tretrauit/scripts/-/raw/main/Apps/ws-scrcpy/ws-scrcp
chmod +x ws-scrcpy-launcher.py
```
+ The script will tell you to wait for ws-scrcpy to start, and when it starts it'll show the started message with the ip address and the port to access using browsers
- The script will tell you to wait for ws-scrcpy to start, and when it starts it'll show the started message with the ip address and the port to access using browsers
> You need to use `adb pair` to pair termux with your device adb server, then you can launch ws-scrcpy as explained above.

View File

@ -1,4 +0,0 @@
# Scripts for Arena of Valor
Scripts I created for this game, thats it. (Not cheating scripts in-game tho)
## Scripts
+ [AWC_AutoSpin.sh](./AWC_AutoSpin.sh) - Auto spin the wheel in AWC website (Works in Vietnamese AOV only, other region need to tweak some string into their language)

View File

@ -1,114 +0,0 @@
// 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

@ -1,9 +1,12 @@
# Scripts for [Cities: Skylines](https://www.citiesskylines.com/)
Scripts I created for this game, thats it.
### Scripts
+ [NotParadoxLauncher_Win_Proton.sh](./NotParadoxLauncher_Win_Proton.sh) - Install [Not Paradox Launcher] to Cities: Skylines (Windows version running in Linux using Proton)
+ [Win_Proton_dowser_patch.sh](./Win_Proton_dowser_patch.sh) - Replace dowser.exe with Cities.exe so the game can launch without using bloated launcher (for CS Windows version running in Proton)
- [NotParadoxLauncher_Win_Proton.sh](./NotParadoxLauncher_Win_Proton.sh) - Install [Not Paradox Launcher] to Cities: Skylines (Windows version running in Linux using Proton)
- [Win_Proton_dowser_patch.sh](./Win_Proton_dowser_patch.sh) - Replace dowser.exe with Cities.exe so the game can launch without using bloated launcher (for CS Windows version running in Proton)
#### Note
These script I created for my friend because I don't play this game, so if it has any problem then feel free to open a issue, thanks.
These script I created for my friend because I don't play this game, so if it has any problem then feel free to open a issue, thanks.

View File

@ -1,58 +1,71 @@
# leagueoflinux scripts
## `sulaunchhelper2.sh`
This script is a wrapper for `sulaunchhelper2.py` for use with Lutris pre-game launch script.
### Installation
> This script no longer wraps `syscall_check.sh`, if you need to execute that script alongside this one, I recommend you to take a look at [preloader.sh](../../../apps/Lutris#preloadersh)
+ To install you must have `sulaunchhelper2.py` present, if not you can execute these to quickly download them (to current directory):
- To install you must have `sulaunchhelper2.py` present, if not you can execute these to quickly download them (to current directory):
```sh
curl -OL https://raw.githubusercontent.com/CakeTheLiar/launchhelper/master/sulaunchhelper2.py
chmod +x sulaunchhelper2.py
```
+ Then to download `sulaunchhelper2.sh` itself:
- Then to download `sulaunchhelper2.sh` itself:
```sh
curl -OL https://gitlab.com/tretrauit/scripts/-/raw/main/games/LoL/linux/sulaunchhelper2.sh
chmod +x sulaunchhelper2.sh
```
+ After that, copy all these files to the game prefix you want to use, then in Lutris:
- Set pre-launch script in Lutris to where `sulaunchhelper2.sh` is located.
- Disable **Wait for pre-launch script completion**
- Enable **Disable Lutris Runtime**
> Failure to do above steps will result in Zenity can't show necessary messages dialog so LoL UI can't launch properly.
+ Enjoy your LoL experience :P
- After that, copy all these files to the game prefix you want to use, then in Lutris: - Set pre-launch script in Lutris to where `sulaunchhelper2.sh` is located. - Disable **Wait for pre-launch script completion** - Enable **Disable Lutris Runtime**
> Failure to do above steps will result in Zenity can't show necessary messages dialog so LoL UI can't launch properly.
- Enjoy your LoL experience :P
## [`discord_rpc.sh`](../../../apps/Lutris#discord_rpcsh)
+ This script will bridge Discord RPC from LoL prefix to your linux Discord.
> Note: The script in current directory [`discord_rpc.sh`](./discord_rpc.sh) is modified from the script mentioned above to work properly with `sulaunchhelper2.sh`,
the installation is the same **except** when installing the script itself, execute this instead:
- This script will bridge Discord RPC from LoL prefix to your linux Discord.
> Note: The script in current directory [`discord_rpc.sh`](./discord_rpc.sh) is modified from the script mentioned above to work properly with `sulaunchhelper2.sh`,
> the installation is the same **except** when installing the script itself, execute this instead:
```sh
curl -OL https://gitlab.com/tretrauit/scripts/-/raw/main/games/LoL/linux/discord_rpc.sh
chmod +x discord_rpc.sh
```
## Deprecated
### `garena_wrapper.sh`
> Garena no longer owns LoL so to play LoL you need to use Rito Client.
This script automates the launching of [lol.py](https://github.com/nhubaotruong/league-of-legends-linux-garena-script) (LoL in Garena client) so you don't have to manually do it ;)
#### Installation
> This script no longer wraps `syscall_check.sh`, if you need to execute that script alongside this one, I recommend you to take a look at [`preloader.sh`](../../../apps/Lutris#preloadersh)
If you plan to use `preloader.sh` then I **highly recommend you** to **disable logging**, because **lol.py and `preloader.sh` will log your token to ./preloader/preloader_garena_wrapper.sh.log if you keep it enabled**, hence your account may get compromised.
> If you plan to use `preloader.sh` then I **highly recommend you** to **disable logging**, because **lol.py and `preloader.sh` will log your token to ./preloader/preloader_garena_wrapper.sh.log if you keep it enabled**, hence your account may get compromised.
You need to follow steps in `lol.py` repository to properly config your LoL prefix.
+ To install you must have `lol.py` present, if not you can execute these to quickly download them (to current directory):
- To install you must have `lol.py` present, if not you can execute these to quickly download them (to current directory):
```sh
curl -OL https://raw.githubusercontent.com/nhubaotruong/league-of-legends-linux-garena-script/main/lol.py
chmod +x lol.py
```
+ Then to download `garena_wrapper.sh` itself:
- Then to download `garena_wrapper.sh` itself:
```sh
curl -OL https://gitlab.com/tretrauit/scripts/-/raw/main/games/LoL/linux/garena_wrapper.sh
chmod +x garena_wrapper.sh
```
+ After that, copy all these files to the game prefix you want to use, then in Lutris:
- Set pre-launch script in Lutris to where `garena_wrapper.sh` is located.
- Disable **Wait for pre-launch script completion**
- Enable **Disable Lutris Runtime**
> Failure to do above steps will result in Zenity can't show necessary messages dialog so LoL UI may not launch properly (it'll still launch if you use `sulaunchhelper2.sh` and have installed it correctly).
+ Enjoy your Garena LoL experience :P
- After that, copy all these files to the game prefix you want to use, then in Lutris: - Set pre-launch script in Lutris to where `garena_wrapper.sh` is located. - Disable **Wait for pre-launch script completion** - Enable **Disable Lutris Runtime**
> Failure to do above steps will result in Zenity can't show necessary messages dialog so LoL UI may not launch properly (it'll still launch if you use `sulaunchhelper2.sh` and have installed it correctly).
- Enjoy your Garena LoL experience :P

View File

@ -12,12 +12,16 @@
// @downloadURL https://gitlab.com/tretrauit/scripts/-/raw/main/userscripts/anonyviet-skip-wait.user.js
// ==/UserScript==
const REDIRECT_PAGE = "https://anonyviet.com/tieptucdentrangmoi/?url="
const REDIRECT_PAGE = "https://anonyviet.com/tieptucdentrangmoi/?url=";
for (const element of document.getElementsByTagName("a")) {
try {
if (element.getAttribute("href").startsWith(REDIRECT_PAGE)) {
element.setAttribute("href", decodeURIComponent(element.getAttribute("href").substring(REDIRECT_PAGE.length)))
}
} catch (_) {
try {
if (element.getAttribute("href").startsWith(REDIRECT_PAGE)) {
element.setAttribute(
"href",
decodeURIComponent(
element.getAttribute("href").substring(REDIRECT_PAGE.length),
),
);
}
} catch (_) {}
}

View File

@ -13,16 +13,20 @@
// ==/UserScript==
setTimeout(() => {
const header = document.querySelector(".src-components-common-TopBar-assets-__pc_---top---uiHfPh");
const header = document.querySelector(
".src-components-common-TopBar-assets-__pc_---top---uiHfPh",
);
if (header != null) {
header.remove()
console.log("Removed header")
header.remove();
console.log("Removed header");
}
setTimeout(() => {
const watermark = document.querySelector(".src-components-pages-assets-__kv_---kv-slogan---IBwwuz.kv-slogan");
const watermark = document.querySelector(
".src-components-pages-assets-__kv_---kv-slogan---IBwwuz.kv-slogan",
);
if (watermark != null) {
watermark.remove()
console.log("Removed watermark")
watermark.remove();
console.log("Removed watermark");
}
}, 5000);
}, 5000);

View File

@ -12,25 +12,27 @@
// @downloadURL https://gitlab.com/tretrauit/scripts/-/raw/main/userscripts/hidemy.name-free-ipport-export.user.js
// ==/UserScript==
setTimeout(function() {
const tblContent = document.getElementsByClassName("table_block")[0].getElementsByTagName("tbody")[0].children
setTimeout(function () {
const tblContent = document
.getElementsByClassName("table_block")[0]
.getElementsByTagName("tbody")[0].children;
// Replace the export IP:Port button
const btns = document.getElementsByClassName("export")[0]
const exportBtn = btns.children[0]
const fakeExportBtn = exportBtn.cloneNode(true)
fakeExportBtn.removeAttribute("href")
fakeExportBtn.addEventListener("click", () => {
var proxyStr = ""
for (let proxyContent of tblContent) {
const proxyContentChildren = proxyContent.children
const proxyIp = proxyContentChildren[0].innerHTML
const proxyPort = proxyContentChildren[1].innerHTML
proxyStr += proxyIp + ":" + proxyPort + "\n"
}
navigator.clipboard.writeText(proxyStr)
alert("Copied IP:Port list to clipboard.")
})
exportBtn.remove()
btns.prepend(fakeExportBtn)
// Replace the export IP:Port button
const btns = document.getElementsByClassName("export")[0];
const exportBtn = btns.children[0];
const fakeExportBtn = exportBtn.cloneNode(true);
fakeExportBtn.removeAttribute("href");
fakeExportBtn.addEventListener("click", () => {
var proxyStr = "";
for (let proxyContent of tblContent) {
const proxyContentChildren = proxyContent.children;
const proxyIp = proxyContentChildren[0].innerHTML;
const proxyPort = proxyContentChildren[1].innerHTML;
proxyStr += proxyIp + ":" + proxyPort + "\n";
}
navigator.clipboard.writeText(proxyStr);
alert("Copied IP:Port list to clipboard.");
});
exportBtn.remove();
btns.prepend(fakeExportBtn);
}, 5000);

View File

@ -14,81 +14,88 @@
// ==/UserScript==
function init() {
const chest = document.getElementsByClassName("chest")[0]
const chestStatus = document.getElementsByClassName("chest__btn btn")[0]
const openWheelBtn = document.getElementsByClassName("wheel__btn")[0]
const upgradeBtn = document.getElementsByClassName("card__upgrade")[0]
// Has string characters need to be removed first.
const requiredScore = document.getElementsByClassName("card__note")[0].getElementsByTagName("strong")[0]
const currentScore = document.getElementsByClassName("card__data")[0].getElementsByTagName("span")[1]
const chest = document.getElementsByClassName("chest")[0];
const chestStatus = document.getElementsByClassName("chest__btn btn")[0];
const openWheelBtn = document.getElementsByClassName("wheel__btn")[0];
const upgradeBtn = document.getElementsByClassName("card__upgrade")[0];
// Has string characters need to be removed first.
const requiredScore = document
.getElementsByClassName("card__note")[0]
.getElementsByTagName("strong")[0];
const currentScore = document
.getElementsByClassName("card__data")[0]
.getElementsByTagName("span")[1];
function toInt(str) {
return parseInt(str.replace(/[^0-9]/g, ''))
function toInt(str) {
return parseInt(str.replace(/[^0-9]/g, ""));
}
function upgradeRank() {
if (toInt(currentScore.innerHTML) >= toInt(requiredScore.innerHTML)) {
upgradeBtn.click();
}
}
function upgradeRank() {
if (toInt(currentScore.innerHTML) >= toInt(requiredScore.innerHTML)) {
upgradeBtn.click()
function receiveRankReward() {
const rewards = document.getElementsByClassName("milestone available");
for (const reward of rewards) {
if (reward.className.includes("claimed")) {
continue;
}
reward.click();
}
}
function spinWheel() {
const spinBtn = document.getElementsByClassName("popup-wheel__btn")[0];
const spinLeft = spinBtn.children[1].getElementsByTagName("strong")[0];
function doSpin() {
spinBtn.click();
setTimeout(() => {
if (parseInt(spinLeft.innerHTML) > 0) {
setTimeout(doSpin, 1000);
}
}, 3000);
}
doSpin();
const closeBtn = document.getElementsByClassName("close")[0];
closeBtn.click();
}
function receiveRankReward() {
const rewards = document.getElementsByClassName("milestone available")
for (const reward of rewards) {
if (reward.className.includes("claimed")) {
continue
}
reward.click()
}
function wheel() {
if (
!openWheelBtn.className.includes("animate__tada") ||
document.getElementById("wheel") != null
) {
return;
}
console.log("click chest");
openWheelBtn.click();
setTimeout(spinWheel, 1000);
}
function spinWheel() {
const spinBtn = document.getElementsByClassName("popup-wheel__btn")[0]
const spinLeft = spinBtn.children[1].getElementsByTagName("strong")[0]
function doSpin() {
spinBtn.click()
setTimeout(() => {
if (parseInt(spinLeft.innerHTML) > 0) {
setTimeout(doSpin, 1000)
}
}, 3000)
}
doSpin()
const closeBtn = document.getElementsByClassName("close")[0]
closeBtn.click()
function receiveScore() {
if (chestStatus.innerHTML === "Nhận") {
chest.click();
}
}
function wheel() {
if (!openWheelBtn.className.includes("animate__tada") || document.getElementById("wheel") != null) {
return
}
console.log("click chest")
openWheelBtn.click()
setTimeout(spinWheel, 1000)
setInterval(() => {
if ((element = document.getElementsByClassName("swal2-close")[0])) {
element.click();
}
}, 100);
function receiveScore() {
if (chestStatus.innerHTML === "Nhận") {
chest.click()
}
}
setInterval(() => {
if (element = document.getElementsByClassName("swal2-close")[0]) {
element.click()
}
}, 100);
function loop() {
receiveScore()
upgradeRank()
receiveRankReward()
setTimeout(wheel, 500)
setTimeout(loop, 1000)
}
loop()
function loop() {
receiveScore();
upgradeRank();
receiveRankReward();
setTimeout(wheel, 500);
setTimeout(loop, 1000);
}
loop();
}
setTimeout(init, 5000)
setTimeout(init, 5000);
console.warn("[8thang5 - Auto farm] Successfully loaded")
console.log("Made by @tretrauit under MIT License")
console.warn("[8thang5 - Auto farm] Successfully loaded");
console.log("Made by @tretrauit under MIT License");

View File

@ -13,65 +13,69 @@
// ==/UserScript==
function injectCSS(css) {
const style = document.createElement('style');
const style = document.createElement("style");
style.appendChild(document.createTextNode(css));
document.head.appendChild(style);
}
function findElement(tag, properties) {
const elements = document.querySelectorAll(tag);
elementLoop:
for (const element of elements) {
for (const [key, value] of Object.entries(properties)) {
if (element.getAttribute(key) != value) {
continue elementLoop;
}
}
return element;
const elements = document.querySelectorAll(tag);
elementLoop: for (const element of elements) {
for (const [key, value] of Object.entries(properties)) {
if (element.getAttribute(key) != value) {
continue elementLoop;
}
}
return element;
}
}
function getAncestor(element, level) {
if (element == null) {
return null;
}
for (let i = 0; i < level; i++) {
element = element.parentNode;
}
return element;
if (element == null) {
return null;
}
for (let i = 0; i < level; i++) {
element = element.parentNode;
}
return element;
}
console.log("Scanning class for components...");
// Search box
let searchBox = findElement("input", {"aria-autocomplete": "list"});
let searchBox = findElement("input", { "aria-autocomplete": "list" });
if (searchBox == null) {
console.warn("Failed to get searchBox element.");
throw new Error();
console.warn("Failed to get searchBox element.");
throw new Error();
}
searchBox = getAncestor(searchBox, 7);
// Header & Text header
let textHeader = findElement("span", {"style": "line-height: var(--base-line-clamp-line-height); --base-line-clamp-line-height:28px;"});
let textHeader = findElement("span", {
style:
"line-height: var(--base-line-clamp-line-height); --base-line-clamp-line-height:28px;",
});
let header;
if (textHeader == null) {
console.warn("Failed to get textHeader element.");
throw new Error();
console.warn("Failed to get textHeader element.");
throw new Error();
}
header = getAncestor(textHeader, 7);
textHeader = textHeader.childNodes[0];
// Unread indicator
let unreadIndicator = findElement("span", {"data-visualcompletion": "ignore"});
let unreadIndicator = findElement("span", {
"data-visualcompletion": "ignore",
});
// Action bar
let actionBar = findElement("div", {"aria-expanded": "false"});
let actionBar = findElement("div", { "aria-expanded": "false" });
if (actionBar == null) {
console.warn("Failed to get actionBar element.");
throw new Error();
console.warn("Failed to get actionBar element.");
throw new Error();
}
actionBar = actionBar.parentNode;
// Chats
let chats = findElement("div", {"aria-label": "Chats"});
let chats = findElement("div", { "aria-label": "Chats" });
if (chats == null) {
console.warn("Failed to get chats element.");
throw new Error();
console.warn("Failed to get chats element.");
throw new Error();
}
chats = chats.parentNode;
// Print elements

View File

@ -13,19 +13,24 @@
// ==/UserScript==
// Remove the "download app ads"
const dlClasses = ["tiktok-9er52i-DivCtaGuideWrapper", "tiktok-99ed1t-DivFooterGuide", "tiktok-txik7e-DivFloatButtonWrapper", "tiktok-h0mxry-DivCtaContentWrapper"]
const dlClasses = [
"tiktok-9er52i-DivCtaGuideWrapper",
"tiktok-99ed1t-DivFooterGuide",
"tiktok-txik7e-DivFloatButtonWrapper",
"tiktok-h0mxry-DivCtaContentWrapper",
];
setInterval(() => {
for (const dlClass of dlClasses) {
const element = document.getElementsByClassName(dlClass)[0]
if (element === undefined) {
continue
}
for (const childElm of element.children) {
console.log(childElm)
setTimeout(() => element.removeChild(childElm), 1)
}
element.style["height"] = "0px"
element.style["padding"] = "0px"
element.style["z-index"] = "-1"
for (const dlClass of dlClasses) {
const element = document.getElementsByClassName(dlClass)[0];
if (element === undefined) {
continue;
}
}, 50)
for (const childElm of element.children) {
console.log(childElm);
setTimeout(() => element.removeChild(childElm), 1);
}
element.style["height"] = "0px";
element.style["padding"] = "0px";
element.style["z-index"] = "-1";
}
}, 50);

View File

@ -24,20 +24,19 @@ function logDebug(...kwargs) {
console.log(...kwargs);
}
function getShortsId(videoPathName)
{
const shortPath = videoPathName.split("/")
return shortPath[shortPath.length - 1]
function getShortsId(videoPathName) {
const shortPath = videoPathName.split("/");
return shortPath[shortPath.length - 1];
}
function redirectReplace() {
window.location.replace("https://www.youtube.com/watch?v=" + getShortsId(window.location.pathname));
window.location.replace(
"https://www.youtube.com/watch?v=" + getShortsId(window.location.pathname),
);
}
function checkCurrentURL()
{
if (window.location.pathname.includes("/shorts/"))
{
function checkCurrentURL() {
if (window.location.pathname.includes("/shorts/")) {
logDebug("Shorts url detected, redirecting...");
redirectReplace();
}
@ -46,22 +45,19 @@ function checkCurrentURL()
// Should be run asap
checkCurrentURL();
function replaceHrefURL(element)
{
if (element.href != null && element.href.includes("/shorts/"))
{
element.href = "/watch?v=" + getShortsId(element.href)
function replaceHrefURL(element) {
if (element.href != null && element.href.includes("/shorts/")) {
element.href = "/watch?v=" + getShortsId(element.href);
}
}
function checkElements()
{
insertionQ(':is(#video-title, #thumbnail) ').every(function(element) {
function checkElements() {
insertionQ(":is(#video-title, #thumbnail) ").every(function (element) {
replaceHrefURL(element);
});
}
window.addEventListener('yt-navigate-finish', checkCurrentURL);
window.addEventListener("yt-navigate-finish", checkCurrentURL);
// Replace addEventListener with our sus one.
const o_addEventListener = window.addEventListener;
const o_shady_addEventListener = window.__shady_addEventListener;
@ -89,17 +85,21 @@ function f_addEventListener(eventName, callback) {
// This event is made by SponsorBlock not Youtube so by default it will not run.
// But this can speed up the page navigation process so i'll just keep it.
const data = event.data;
if (data.type == 'navigation' && data.pageType == 'shorts') {
if (data.type == "navigation" && data.pageType == "shorts") {
if (data.videoID == undefined) {
return;
}
logDebug("Thank you SponsorBlock for this event :3");
logDebug("Navigating to video...");
if (window.location.pathname.includes("/shorts/")) {
window.location.replace("https://www.youtube.com/watch?v=" + data.videoID);
window.location.replace(
"https://www.youtube.com/watch?v=" + data.videoID,
);
return;
}
window.location.assign("https://www.youtube.com/watch?v=" + data.videoID);
window.location.assign(
"https://www.youtube.com/watch?v=" + data.videoID,
);
return;
}
}
@ -117,4 +117,4 @@ logDebug("Init fake addEventListener successful.");
window.__shady_addEventListener = f_sus_addEventListener;
logDebug("Init fake __shady_addEventListener successful.");
checkElements();
console.warn("Fuck you YouTube - NoShorts loaded.")
console.warn("Fuck you YouTube - NoShorts loaded.");

View File

@ -1,6 +1,8 @@
# UserStyles
# UserStyles
Contains random UserStyles.
## UserStyles list
+ [Messenger Dynamic Sidebar](./messenger-dynamic-sidebar.user.css): [reizumi](https://codeberg.org/reizumi)'s Messenger Dynamic Sidebar ported to pure CSS for Ferdium support
> Ported from commit [`1cb2a5b12ad2d04d8c3932892108b6be05528c6f`](https://codeberg.org/reizumi/userstyles/commit/1cb2a5b12ad2d04d8c3932892108b6be05528c6f)
- [Messenger Dynamic Sidebar](./messenger-dynamic-sidebar.user.css): [reizumi](https://codeberg.org/reizumi)'s Messenger Dynamic Sidebar ported to pure CSS for Ferdium support
> Ported from commit [`1cb2a5b12ad2d04d8c3932892108b6be05528c6f`](https://codeberg.org/reizumi/userstyles/commit/1cb2a5b12ad2d04d8c3932892108b6be05528c6f)

View File

@ -1,96 +1,104 @@
:root {
--sidebarSpeed: .2s;
--sidebarDelay: .1s;
--actionBarDelay: .15s;
--sidebarEase: "ease";
--sidebarWidth: 360px;
--sidebarSpeed: 0.2s;
--sidebarDelay: 0.1s;
--actionBarDelay: 0.15s;
--sidebarEase: "ease";
--sidebarWidth: 360px;
}
.bdao358l.om3e55n1.g4tp4svg.alzwoclg.cqf1kptm.jez8cy9q.gvxzyvdx.aeinzg81.qp72b3h3.oxkhqvkx.nch0832m.srn514ro.rl78xhln {
max-width: 0;
overflow: hidden;
border-right-color: var(--web-wash);
transition: max-width var(--sidebarSpeed);
transition-delay: var(--actionBarDelay);
max-width: 0;
overflow: hidden;
border-right-color: var(--web-wash);
transition: max-width var(--sidebarSpeed);
transition-delay: var(--actionBarDelay);
}
.bdao358l.om3e55n1.g4tp4svg.alzwoclg.cqf1kptm.jez8cy9q.gvxzyvdx.aeinzg81.qp72b3h3.oxkhqvkx.nch0832m.srn514ro.rl78xhln:hover {
max-width: 211px;
border-right-color: var(--media-inner-border);
max-width: 211px;
border-right-color: var(--media-inner-border);
}
/* Header */
.mm98tyaj .bdao358l.om3e55n1.g4tp4svg.alzwoclg.jez8cy9q.sl27f92c.i85zmo3j.sr926ui1.jl2a5g8c.anf3k8p9.rj0o91l8.qjfq86k5.p9ctufpz.lth9pzmp {
opacity: 0;
height: 0;
margin: 0 16px;
overflow: hidden;
transition: var(--sidebarSpeed);
.mm98tyaj
.bdao358l.om3e55n1.g4tp4svg.alzwoclg.jez8cy9q.sl27f92c.i85zmo3j.sr926ui1.jl2a5g8c.anf3k8p9.rj0o91l8.qjfq86k5.p9ctufpz.lth9pzmp {
opacity: 0;
height: 0;
margin: 0 16px;
overflow: hidden;
transition: var(--sidebarSpeed);
}
/* Search */
.mm98tyaj .bdao358l.om3e55n1.g4tp4svg.r227ecj6.gt60zsk1.rj2hsocd.f9xcifuu {
opacity: 0;
height: 0;
overflow: hidden;
transition: var(--sidebarSpeed);
opacity: 0;
height: 0;
overflow: hidden;
transition: var(--sidebarSpeed);
}
/* Text Header */
.mm98tyaj .jxuftiz4.jwegzro5.hl4rid49.icdlwmnq {
width: 150px;
width: 150px;
}
/* Unread Message Indicator */
.mm98tyaj .nmlomj2f[data-visualcompletion="ignore"] {
position: relative;
right: 83px;
transition-delay: var(--sidebarDelay);
position: relative;
right: 83px;
transition-delay: var(--sidebarDelay);
}
/* Notification bell */
.mm98tyaj .sr926ui1.alzwoclg.i85zmo3j svg,
.mm98tyaj .sr926ui1.alzwoclg.i85zmo3j .i1ozlmoo {
display: none;
display: none;
}
/* Scrollbar */
.mm98tyaj .alzwoclg.cqf1kptm.cgu29s5g.i15ihif8.sl4bvocy.lq84ybu9.efm7ts3d.om3e55n1.mfclru0v {
overflow-y: hidden;
.mm98tyaj
.alzwoclg.cqf1kptm.cgu29s5g.i15ihif8.sl4bvocy.lq84ybu9.efm7ts3d.om3e55n1.mfclru0v {
overflow-y: hidden;
}
/* Hide contents (workaround) */
.i85zmo3j.alzwoclg.rtxb060y.p4zypb3t {
overflow: hidden;
overflow: hidden;
}
/* Sidebar (not focused) */
.mm98tyaj {
width: 80px;
min-width: 80px;
transition: width var(--sidebarSpeed) var(--sidebarEase);
transition-delay: var(--sidebarDelay);
width: 80px;
min-width: 80px;
transition: width var(--sidebarSpeed) var(--sidebarEase);
transition-delay: var(--sidebarDelay);
}
/* Sidebar (focused) */
.b0ur3jhr:hover .mm98tyaj {
width: var(--sidebarWidth);
transition-delay: 0s;
width: var(--sidebarWidth);
transition-delay: 0s;
}
/* Header (focused) */
.b0ur3jhr:hover .mm98tyaj .bdao358l.om3e55n1.g4tp4svg.alzwoclg.jez8cy9q.sl27f92c.i85zmo3j.sr926ui1.jl2a5g8c.anf3k8p9.rj0o91l8.qjfq86k5.p9ctufpz.lth9pzmp {
opacity: 1;
height: auto;
overflow: visible;
margin: 20px 16px 12px 16px;
.b0ur3jhr:hover
.mm98tyaj
.bdao358l.om3e55n1.g4tp4svg.alzwoclg.jez8cy9q.sl27f92c.i85zmo3j.sr926ui1.jl2a5g8c.anf3k8p9.rj0o91l8.qjfq86k5.p9ctufpz.lth9pzmp {
opacity: 1;
height: auto;
overflow: visible;
margin: 20px 16px 12px 16px;
}
/* Search (focused) */
.b0ur3jhr:hover .mm98tyaj .bdao358l.om3e55n1.g4tp4svg.r227ecj6.gt60zsk1.rj2hsocd.f9xcifuu {
opacity: 1;
height: auto;
overflow: visible;
.b0ur3jhr:hover
.mm98tyaj
.bdao358l.om3e55n1.g4tp4svg.r227ecj6.gt60zsk1.rj2hsocd.f9xcifuu {
opacity: 1;
height: auto;
overflow: visible;
}
/* Unread Message Indicator (focused) */
.b0ur3jhr:hover .mm98tyaj .nmlomj2f[data-visualcompletion="ignore"] {
right: 0;
transition-delay: 0s;
right: 0;
transition-delay: 0s;
}
/* Notification bell (focused) */
.b0ur3jhr:hover .mm98tyaj .sr926ui1.alzwoclg.i85zmo3j svg,
.b0ur3jhr:hover .mm98tyaj .sr926ui1.alzwoclg.i85zmo3j .i1ozlmoo {
display: block;
display: block;
}
/* Scrollbar (focused) */
.b0ur3jhr:hover .mm98tyaj .alzwoclg.cqf1kptm.cgu29s5g.i15ihif8.sl4bvocy.lq84ybu9.efm7ts3d.om3e55n1.mfclru0v {
overflow-y: scroll;
.b0ur3jhr:hover
.mm98tyaj
.alzwoclg.cqf1kptm.cgu29s5g.i15ihif8.sl4bvocy.lq84ybu9.efm7ts3d.om3e55n1.mfclru0v {
overflow-y: scroll;
}

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

@ -1,16 +1,16 @@
if (!window.location.href.startsWith("https://apl2022.lienquan.garena.vn")) {
console.error("This script is for https://apl2022.lienquan.garena.vn only.");
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: `
const rsp = await fetch("/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
operationName: "getUser",
query: `
query getUser {
getUser {
id
@ -49,24 +49,24 @@ async function getCurrentUser() {
__typename
}
`,
variables: {},
}),
})
if (!rsp.ok) {
throw `Failed to get current user info`
}
return (await rsp.json()).data.getUser;
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: `
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
@ -99,41 +99,41 @@ async function postClick(amount) {
__typename
}
`,
variables: {
clicks: amount,
},
}),
})
if (!rsp.ok) {
throw `Failed to post click request with amount ${amount}`
}
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.");
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()
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();