Skip to content

Commit

Permalink
🎉 Add auto-start functionality to content script
Browse files Browse the repository at this point in the history
This commit adds a new file `auto-start.ts` that contains the logic for automatically starting a game. The `startObserver` function creates a MutationObserver instance to monitor changes in the document. When the observer detects a change, it checks if the current URL is a lobby page and not a new lobby page. If so, it disconnects itself, initializes auto-start using the `initAutoStart` function, and then reconnects after 1 second.

The `initAutoStart` function checks if an element with id "auto-start-toggle" exists. If not, it waits for specific elements to load using the `waitForElement` helper function. Once all required elements are available, it creates a toggle button and appends it to the buttons container element. It also removes any duplicate toggle buttons if present.

The `checkAutoStart` function periodically checks if there are more than one row in a specific table on the page. If so, it retrieves the start button element and triggers a click event on it.

Additionally, this commit adds a new file `helpers/index.ts` that contains the implementation of the `waitForElement` helper function used in `auto-start.ts`. This function waits for an element matching a given selector to appear within a specified timeout period.

Finally, in `index.ts`, we import and use the newly added `auto-start.ts`.
  • Loading branch information
creazy231 committed Feb 2, 2024
1 parent 5909e7d commit 235b748
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# These are supported funding model platforms

github: creazy231
ko_fi: creazy231
custom: https://paypal.me/thiele231
13 changes: 13 additions & 0 deletions .github/workflows/build.pull-request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: build.pull_request
'on': pull_request
jobs:
build_and_preview:
if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: yarn install --no-frozen-lockfile
- run: yarn build
15 changes: 15 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: build
'on':
push:
branches:
- master
jobs:
build_and_deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: yarn install --no-frozen-lockfile
- run: yarn build
53 changes: 53 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: release
'on':
push:
branches:
- master

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: true

defaults:
run:
shell: 'bash'

jobs:
draft_release:
permissions:
contents: write # Allows this job to create releases

strategy:
fail-fast: true
matrix:
# os: [macos-latest, ubuntu-latest, windows-latest]
os: [ubuntu-latest]

runs-on: ${{ matrix.os }}
timeout-minutes: 5

steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
# cache: 'npm'

- run: npm i
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1

- name: Get Package Version
id: get-version
run: echo "::set-output name=version::$(node -p "require('./package.json').version")"

- run: npm run build
- run: zip -r ${{ steps.get-version.outputs.version }}.zip dist

- name: GH Release
uses: softprops/action-gh-release@v0.1.15
with:
tag_name: ${{ steps.get-version.outputs.version }}
release_name: ${{ steps.get-version.outputs.version }}
draft: true
files: ${{ steps.get-version.outputs.version }}.zip
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,3 @@ dist-ssr
*.njsproj
*.sln
*.sw?

.github
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@
"preview": "vite preview"
},
"type": "module",
"version": "0.0.1"
"version": "0.0.2"
}
85 changes: 85 additions & 0 deletions src/content-script/auto-start.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Create a MutationObserver instance
import { waitForElement } from "@/content-script/helpers";

let observer: MutationObserver;

let checkAutoStartInterval: NodeJS.Timeout;

function startObserver() {
console.log("Observer started");
observer = new MutationObserver((mutationsList, observer) => {
for (const mutation of mutationsList) {
if (mutation.type === "childList") {
if (window.location.href.includes("/lobbies/") && !window.location.href.includes("/new")) {
observer.disconnect();
console.log("Observer disconnected");
initAutoStart().catch(err => console.error(err));

setTimeout(() => {
observer.observe(document, { childList: true, subtree: true });
console.log("Observer reconnected");
}, 1000);
} else {
if (checkAutoStartInterval) clearInterval(checkAutoStartInterval);
}
}
}
});

// Start observing the document with the configured parameters
observer.observe(document, { childList: true, subtree: true });
}

startObserver();

async function initAutoStart() {
// check if element with id "auto-start-toggle" exists. if yes, return
const toggleElement = document.getElementById("auto-start-toggle");
if (toggleElement) return;

const startButton = await waitForElement("#root > div:nth-of-type(2) > div:nth-of-type(3) > div > button:nth-of-type(1)");
const deleteButton = await waitForElement("#root > div:nth-of-type(2) > div:nth-of-type(3) > div > button:nth-of-type(2)");
const buttonsElement = await waitForElement("#root > div:nth-of-type(2) > div:nth-of-type(3) > div");

if (startButton && deleteButton && buttonsElement) {
console.log("START GAME");
// create a toggle with on and off and add it to the buttonsElement
const toggle = document.createElement("button");
toggle.id = "auto-start-toggle";
toggle.className = "auto-start-toggle";
toggle.innerText = "Auto Start: OFF";
const defaultStyles = "color: var(--chakra-colors-red-500); background: var(--chakra-colors-whiteAlpha-300); padding-inline-start: var(--chakra-space-6); padding-inline-end: var(--chakra-space-6); line-height: 3; border-radius: var(--chakra-radii-md); font-weight: bold;";
toggle.setAttribute("style", defaultStyles);

toggle.addEventListener("click", () => {
if (toggle.innerText.includes("OFF")) {
toggle.innerText = "Auto Start: ON";
toggle.setAttribute("style", `${defaultStyles}color: var(--chakra-colors-green-500);`);
checkAutoStartInterval = setInterval(checkAutoStart, 1000);
} else {
toggle.innerText = "Auto Start: OFF";
toggle.setAttribute("style", `${defaultStyles}color: var(--chakra-colors-red-500);`);
if (checkAutoStartInterval) clearInterval(checkAutoStartInterval);
}
});
buttonsElement.appendChild(toggle);

// check if there are multiple elements with class "auto-start-toggle". if yes, remove all except the last one
const toggles = document.querySelectorAll(".auto-start-toggle");
if (toggles.length > 1) {
for (let i = 0; i < toggles.length - 1; i++) {
toggles[i].remove();
}
}
}
}

function checkAutoStart() {
// check if querySelectorAll "#root > div:nth-of-type(2) > div:nth-of-type(2) > div > table tr" contains more than 1 row
const rows = document.querySelectorAll("#root > div:nth-of-type(2) > div:nth-of-type(2) > div > table > tbody > tr");
if (rows.length > 1) {
// get the "startButton" again and click it
const startButton = document.querySelector("#root > div:nth-of-type(2) > div:nth-of-type(3) > div > button:nth-of-type(1)");
startButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
}
}
16 changes: 16 additions & 0 deletions src/content-script/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export function waitForElement(selector: string, timeout = 3000): Promise<HTMLElement | undefined> {
return new Promise((resolve, reject) => {
const startTime = Date.now();
const timer = setInterval(() => {
const element = document.querySelector(selector);
if (element) {
clearInterval(timer);
// @ts-expect-error
resolve(element);
} else if (Date.now() - startTime >= timeout) {
clearInterval(timer);
resolve(undefined);
}
}, 100);
});
}
1 change: 1 addition & 0 deletions src/content-script/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import "./index.scss";
import "./auto-start";
import { useLocalStorage } from "@/composables/useLocalStorage";

const { get, set } = useLocalStorage();
Expand Down

0 comments on commit 235b748

Please sign in to comment.