From 155fa84eda592002cf628ba0d486474915f4a870 Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Mon, 25 Aug 2025 20:28:48 +0200
Subject: [PATCH 01/14] ci??
---
.github/workflows/deploy.yml | 187 +++++++++++++++++++++++++++++++++++
1 file changed, 187 insertions(+)
create mode 100644 .github/workflows/deploy.yml
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..b7f9f1d
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,187 @@
+name: Continuous Deployment
+
+on:
+ push:
+ branches:
+ - "**"
+
+# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+ actions: read
+
+# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
+concurrency:
+ group: "pages"
+ cancel-in-progress: true
+
+jobs:
+ build_matrix:
+ runs-on: ubuntu-latest
+ outputs:
+ json_branches: ${{ steps.generate-matrix.outputs.json_branches }}
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Generate Matrix
+ id: generate-matrix
+ run: |
+ branches=($(git branch -r | cut -c 3- | sed 's/origin\///g'))
+ json_branches=$(printf '%s\n' "${branches[@]}" | jq -R . | jq -s -c .)
+ echo "json_branches=${json_branches}" >> $GITHUB_OUTPUT
+
+ collect_files:
+ runs-on: ubuntu-latest
+ name: Collect Files
+ needs:
+ - build_matrix
+ strategy:
+ matrix:
+ branch: ${{ fromJSON(needs.build_matrix.outputs.json_branches) }}
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ matrix.branch }}
+ - name: Collect all files
+ run: |
+ mkdir -p branch_files
+ # Copy all JS, CSS, and other relevant files
+ find . -name "*.js" -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.github/*" -exec cp {} branch_files/ \;
+ find . -name "*.css" -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.github/*" -exec cp {} branch_files/ \;
+ find . -name "*.json" -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.github/*" -not -name "package*.json" -exec cp {} branch_files/ \;
+ find . -name "*.html" -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.github/*" -exec cp {} branch_files/ \;
+ # Copy any other asset files you might need
+ find . -name "*.png" -o -name "*.jpg" -o -name "*.gif" -o -name "*.svg" | grep -v ".git" | grep -v "node_modules" | xargs -I {} cp {} branch_files/ 2>/dev/null || true
+ ls -la branch_files/
+ - uses: actions/upload-artifact@v3
+ with:
+ name: branch-${{ matrix.branch }}-${{ strategy.job-index }}
+ path: branch_files/
+
+ deploy:
+ runs-on: ubuntu-latest
+ name: Deploy
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ needs:
+ - build_matrix
+ - collect_files
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Setup Pages
+ uses: actions/configure-pages@v3
+ - run: gh run download ${{ github.run_id }} --dir branches
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Create public folder structure
+ run: |
+ mkdir public
+ cd public
+ branches=$(echo '${{ needs.build_matrix.outputs.json_branches }}' | jq -r '.[]')
+ i=0
+
+ # Create index.html header
+ cat > index.html << 'EOF'
+
+
+
+
+
+ WPlace AutoBOT - Branch Files
+
+
+
+
+
🚀 WPlace AutoBOT - Branch Files
+
Access files from different branches. Click on file links or copy the bookmarklet code:
+ EOF
+
+ for branch in ${branches}
+ do
+ # Create branch directory
+ mkdir -p "$branch"
+
+ # Find and move the branch files
+ find ../branches -name "branch-${branch}-*" -type d | head -1 | while read dir; do
+ if [ -d "$dir" ]; then
+ cp -r "$dir"/* "./$branch/"
+ fi
+ done
+
+ # Add branch section to index.html
+ echo "
" >> index.html
+ echo "
📁 Branch: $branch " >> index.html
+ echo "
" >> index.html
+
+ # List files in this branch
+ if [ -d "$branch" ]; then
+ for file in "$branch"/*; do
+ if [ -f "$file" ]; then
+ filename=$(basename "$file")
+ echo "
$filename " >> index.html
+ fi
+ done
+
+ # Add bookmarklet examples for JS files
+ for jsfile in "$branch"/*.js; do
+ if [ -f "$jsfile" ]; then
+ filename=$(basename "$jsfile")
+ echo "
" >> index.html
+ echo "
Bookmarklet for $filename: " >> index.html
+ echo "javascript:fetch(\"https://\${GITHUB_USERNAME}.github.io/\${REPO_NAME}/$branch/$filename\").then(t=>t.text()).then(eval);" >> index.html
+ echo "Copy " >> index.html
+ echo "
" >> index.html
+ echo "
" >> index.html
+ fi
+ done
+ fi
+
+ echo "
" >> index.html
+ echo "
" >> index.html
+
+ i=$((i+1))
+ done
+
+ # Close HTML
+ cat >> index.html << 'EOF'
+
+
+
+
+ EOF
+
+ echo "Generated file structure:"
+ ls -lR
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v2
+ with:
+ path: ./public/
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v2
\ No newline at end of file
From d5d34ce1b698b70fff82bb0c12b7eba5469e294b Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Mon, 25 Aug 2025 20:45:47 +0200
Subject: [PATCH 02/14] gone ci, package.json
---
.github/workflows/deploy.yml | 187 ------
.gitignore | 1 +
package-lock.json | 1109 ++++++++++++++++++++++++++++++++++
package.json | 16 +
server.js | 182 ++++++
5 files changed, 1308 insertions(+), 187 deletions(-)
delete mode 100644 .github/workflows/deploy.yml
create mode 100644 .gitignore
create mode 100644 package-lock.json
create mode 100644 package.json
create mode 100644 server.js
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
deleted file mode 100644
index b7f9f1d..0000000
--- a/.github/workflows/deploy.yml
+++ /dev/null
@@ -1,187 +0,0 @@
-name: Continuous Deployment
-
-on:
- push:
- branches:
- - "**"
-
-# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
-permissions:
- contents: read
- pages: write
- id-token: write
- actions: read
-
-# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
-concurrency:
- group: "pages"
- cancel-in-progress: true
-
-jobs:
- build_matrix:
- runs-on: ubuntu-latest
- outputs:
- json_branches: ${{ steps.generate-matrix.outputs.json_branches }}
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- - name: Generate Matrix
- id: generate-matrix
- run: |
- branches=($(git branch -r | cut -c 3- | sed 's/origin\///g'))
- json_branches=$(printf '%s\n' "${branches[@]}" | jq -R . | jq -s -c .)
- echo "json_branches=${json_branches}" >> $GITHUB_OUTPUT
-
- collect_files:
- runs-on: ubuntu-latest
- name: Collect Files
- needs:
- - build_matrix
- strategy:
- matrix:
- branch: ${{ fromJSON(needs.build_matrix.outputs.json_branches) }}
- steps:
- - uses: actions/checkout@v4
- with:
- ref: ${{ matrix.branch }}
- - name: Collect all files
- run: |
- mkdir -p branch_files
- # Copy all JS, CSS, and other relevant files
- find . -name "*.js" -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.github/*" -exec cp {} branch_files/ \;
- find . -name "*.css" -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.github/*" -exec cp {} branch_files/ \;
- find . -name "*.json" -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.github/*" -not -name "package*.json" -exec cp {} branch_files/ \;
- find . -name "*.html" -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./.github/*" -exec cp {} branch_files/ \;
- # Copy any other asset files you might need
- find . -name "*.png" -o -name "*.jpg" -o -name "*.gif" -o -name "*.svg" | grep -v ".git" | grep -v "node_modules" | xargs -I {} cp {} branch_files/ 2>/dev/null || true
- ls -la branch_files/
- - uses: actions/upload-artifact@v3
- with:
- name: branch-${{ matrix.branch }}-${{ strategy.job-index }}
- path: branch_files/
-
- deploy:
- runs-on: ubuntu-latest
- name: Deploy
- environment:
- name: github-pages
- url: ${{ steps.deployment.outputs.page_url }}
- needs:
- - build_matrix
- - collect_files
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- - name: Setup Pages
- uses: actions/configure-pages@v3
- - run: gh run download ${{ github.run_id }} --dir branches
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Create public folder structure
- run: |
- mkdir public
- cd public
- branches=$(echo '${{ needs.build_matrix.outputs.json_branches }}' | jq -r '.[]')
- i=0
-
- # Create index.html header
- cat > index.html << 'EOF'
-
-
-
-
-
- WPlace AutoBOT - Branch Files
-
-
-
-
-
🚀 WPlace AutoBOT - Branch Files
-
Access files from different branches. Click on file links or copy the bookmarklet code:
- EOF
-
- for branch in ${branches}
- do
- # Create branch directory
- mkdir -p "$branch"
-
- # Find and move the branch files
- find ../branches -name "branch-${branch}-*" -type d | head -1 | while read dir; do
- if [ -d "$dir" ]; then
- cp -r "$dir"/* "./$branch/"
- fi
- done
-
- # Add branch section to index.html
- echo "
" >> index.html
- echo "
📁 Branch: $branch " >> index.html
- echo "
" >> index.html
-
- # List files in this branch
- if [ -d "$branch" ]; then
- for file in "$branch"/*; do
- if [ -f "$file" ]; then
- filename=$(basename "$file")
- echo "
$filename " >> index.html
- fi
- done
-
- # Add bookmarklet examples for JS files
- for jsfile in "$branch"/*.js; do
- if [ -f "$jsfile" ]; then
- filename=$(basename "$jsfile")
- echo "
" >> index.html
- echo "
Bookmarklet for $filename: " >> index.html
- echo "javascript:fetch(\"https://\${GITHUB_USERNAME}.github.io/\${REPO_NAME}/$branch/$filename\").then(t=>t.text()).then(eval);" >> index.html
- echo "Copy " >> index.html
- echo "
" >> index.html
- echo "
" >> index.html
- fi
- done
- fi
-
- echo "
" >> index.html
- echo "
" >> index.html
-
- i=$((i+1))
- done
-
- # Close HTML
- cat >> index.html << 'EOF'
-
-
-
-
- EOF
-
- echo "Generated file structure:"
- ls -lR
- - name: Upload artifact
- uses: actions/upload-pages-artifact@v2
- with:
- path: ./public/
- - name: Deploy to GitHub Pages
- id: deployment
- uses: actions/deploy-pages@v2
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b512c09
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..5fe3b60
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1109 @@
+{
+ "name": "wplace-autobot-server",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "wplace-autobot-server",
+ "version": "1.0.0",
+ "dependencies": {
+ "express": "^4.18.2"
+ },
+ "devDependencies": {
+ "nodemon": "^3.0.1"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+ "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.13.0",
+ "raw-body": "2.5.2",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+ "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.21.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+ "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.3",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.7.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.3.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.3",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.12",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.13.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.19.0",
+ "serve-static": "1.16.2",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+ "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/nodemon": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
+ "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
+ "node_modules/nodemon/node_modules/debug": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/nodemon/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+ "dev": true
+ },
+ "node_modules/qs": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+ "dependencies": {
+ "side-channel": "^1.0.6"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+ "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/serve-static": {
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+ "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
+ "dependencies": {
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.19.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/touch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
+ "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
+ "dev": true,
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d6186ff
--- /dev/null
+++ b/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "wplace-autobot-server",
+ "version": "1.0.0",
+ "description": "Local server for hosting WPlace AutoBOT files per branch",
+ "main": "server.js",
+ "scripts": {
+ "start": "node server.js",
+ "dev": "nodemon server.js"
+ },
+ "dependencies": {
+ "express": "^4.18.2"
+ },
+ "devDependencies": {
+ "nodemon": "^3.0.1"
+ }
+}
\ No newline at end of file
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..5c330cb
--- /dev/null
+++ b/server.js
@@ -0,0 +1,182 @@
+const express = require('express');
+const { exec } = require('child_process');
+const fs = require('fs');
+const path = require('path');
+
+const app = express();
+const port = 3000;
+
+// Cache for branch files
+const branchCache = new Map();
+
+// Get all branches and their files
+function getBranchFiles(callback) {
+ exec('git branch -r | cut -c 3- | sed "s/origin\\///g"', (error, stdout, stderr) => {
+ if (error) {
+ console.error('Error getting branches:', error);
+ callback([]);
+ return;
+ }
+
+ const branches = stdout.trim().split('\n').filter(branch => branch && branch !== 'HEAD');
+ const branchData = [];
+
+ let completed = 0;
+ branches.forEach(branch => {
+ exec(`git show ${branch.includes('origin/') ? branch : 'origin/' + branch}:Auto-Farm.js 2>/dev/null`, (err, farmJs) => {
+ exec(`git show ${branch.includes('origin/') ? branch : 'origin/' + branch}:Auto-Image.js 2>/dev/null`, (err2, imageJs) => {
+ exec(`git ls-tree -r --name-only ${branch.includes('origin/') ? branch : 'origin/' + branch} | grep -E "\\.(js|css|html|json)$" 2>/dev/null`, (err3, files) => {
+ const branchFiles = {};
+
+ if (!err && farmJs) branchFiles['Auto-Farm.js'] = farmJs;
+ if (!err2 && imageJs) branchFiles['Auto-Image.js'] = imageJs;
+
+ // Get other files
+ if (!err3 && files) {
+ const fileList = files.trim().split('\n').filter(f => f);
+ let fileCount = fileList.length;
+
+ if (fileCount === 0) {
+ branchData.push({ branch, files: branchFiles });
+ completed++;
+ if (completed === branches.length) callback(branchData);
+ return;
+ }
+
+ fileList.forEach(filename => {
+ if (!branchFiles[path.basename(filename)]) {
+ exec(`git show ${branch.includes('origin/') ? branch : 'origin/' + branch}:${filename} 2>/dev/null`, (err4, content) => {
+ if (!err4 && content) {
+ branchFiles[path.basename(filename)] = content;
+ }
+ fileCount--;
+ if (fileCount === 0) {
+ branchData.push({ branch, files: branchFiles });
+ completed++;
+ if (completed === branches.length) callback(branchData);
+ }
+ });
+ } else {
+ fileCount--;
+ if (fileCount === 0) {
+ branchData.push({ branch, files: branchFiles });
+ completed++;
+ if (completed === branches.length) callback(branchData);
+ }
+ }
+ });
+ } else {
+ branchData.push({ branch, files: branchFiles });
+ completed++;
+ if (completed === branches.length) callback(branchData);
+ }
+ });
+ });
+ });
+ });
+ });
+}
+
+// Serve files per branch
+app.get('/:branch/:filename', (req, res) => {
+ const { branch, filename } = req.params;
+
+ getBranchFiles((branches) => {
+ const branchData = branches.find(b => b.branch === branch || b.branch === `origin/${branch}`);
+
+ if (!branchData || !branchData.files[filename]) {
+ return res.status(404).send('File not found');
+ }
+
+ // Set appropriate content type
+ if (filename.endsWith('.js')) {
+ res.setHeader('Content-Type', 'application/javascript');
+ } else if (filename.endsWith('.css')) {
+ res.setHeader('Content-Type', 'text/css');
+ } else if (filename.endsWith('.html')) {
+ res.setHeader('Content-Type', 'text/html');
+ } else if (filename.endsWith('.json')) {
+ res.setHeader('Content-Type', 'application/json');
+ }
+
+ // Enable CORS for browser scripts
+ res.setHeader('Access-Control-Allow-Origin', '*');
+
+ res.send(branchData.files[filename]);
+ });
+});
+
+// Serve index page
+app.get('/', (req, res) => {
+ getBranchFiles((branches) => {
+ let html = `
+
+
+
+ WPlace AutoBOT - Local Server
+
+
+
+
+
🚀 WPlace AutoBOT - Local Server
+
Server URL: ${req.protocol}://${req.get('host')}
+
Use ngrok to expose this server: ngrok http 3000
+`;
+
+ branches.forEach(branchData => {
+ const branch = branchData.branch.replace('origin/', '');
+ html += `
+
+
📁 Branch: ${branch}
+
+`;
+ Object.keys(branchData.files).forEach(filename => {
+ const url = `${req.protocol}://${req.get('host')}/${branch}/${filename}`;
+ html += `
${filename} `;
+
+ if (filename.endsWith('.js')) {
+ html += `
+
+
+ Bookmarklet for ${filename}:
+ javascript:fetch("${url}").then(t=>t.text()).then(eval);
+ Copy
+
+
`;
+ }
+ });
+ html += `
`;
+ });
+
+ html += `
+
+
+
+
+`;
+
+ res.send(html);
+ });
+});
+
+app.listen(port, () => {
+ console.log(`🚀 WPlace AutoBOT server running at http://localhost:${port}`);
+ console.log(`📡 Run 'ngrok http ${port}' to expose this server publicly`);
+ console.log(`🔗 Then use URLs like: https://abc123.ngrok.io/main/Auto-Farm.js`);
+});
\ No newline at end of file
From abb7402083e917d2caf08f2597f0fcebeea125c9 Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Tue, 26 Aug 2025 18:04:32 +0200
Subject: [PATCH 03/14] wip
---
Auto-Image.js | 50 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 44 insertions(+), 6 deletions(-)
diff --git a/Auto-Image.js b/Auto-Image.js
index 6fae8ba..99aa2f5 100644
--- a/Auto-Image.js
+++ b/Auto-Image.js
@@ -222,7 +222,10 @@
}
}
- // BILINGUAL TEXT STRINGS:)
+ // Simple translation cache
+ const translationCache = new Map();
+
+ // BILINGUAL TEXT STRINGS (FALLBACK):)
const TEXT = {
en: {
title: "WPlace Auto-Image",
@@ -2074,12 +2077,47 @@
return button
},
- t: (key, params = {}) => {
- let text = TEXT[state.language]?.[key] || TEXT.en[key] || key
+ t: async (key, params = {}) => {
+ // Try to get from ngrok first, with caching
+ const cacheKey = `${state.language}_${key}`;
+ if (translationCache.has(cacheKey)) {
+ let text = translationCache.get(cacheKey);
+ Object.keys(params).forEach((param) => {
+ text = text.replace(`{${param}}`, params[param]);
+ });
+ return text;
+ }
+
+ // Try fetching from ngrok
+ try {
+ const response = await fetch(`TODO: /translations/${state.language}.json`, {
+ headers: {
+ "ngrok-skip-browser-warning": "69420"
+ }
+ });
+
+ if (response.ok) {
+ const translations = await response.json();
+ if (translations[key]) {
+ // Cache the successful translation
+ translationCache.set(cacheKey, translations[key]);
+ let text = translations[key];
+ Object.keys(params).forEach((param) => {
+ text = text.replace(`{${param}}`, params[param]);
+ });
+ return text;
+ }
+ }
+ } catch (error) {
+ // Silently fail and use fallback
+ }
+
+ // Fallback to local TEXT
+ let text = TEXT[state.language]?.[key] || TEXT.en[key] || key;
Object.keys(params).forEach((param) => {
- text = text.replace(`{${param}}`, params[param])
- })
- return text
+ text = text.replace(`{${param}}`, params[param]);
+ });
+ return text;
},
showAlert: (message, type = "info") => {
From 26427923b6215e79b6ad2df0ad592326dd4387df Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Wed, 27 Aug 2025 14:51:50 +0200
Subject: [PATCH 04/14] npm be gone
---
package-lock.json | 1109 ---------------------------------------------
package.json | 16 -
2 files changed, 1125 deletions(-)
delete mode 100644 package-lock.json
delete mode 100644 package.json
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 5fe3b60..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,1109 +0,0 @@
-{
- "name": "wplace-autobot-server",
- "version": "1.0.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "wplace-autobot-server",
- "version": "1.0.0",
- "dependencies": {
- "express": "^4.18.2"
- },
- "devDependencies": {
- "nodemon": "^3.0.1"
- }
- },
- "node_modules/accepts": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
- "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
- "dependencies": {
- "mime-types": "~2.1.34",
- "negotiator": "0.6.3"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/anymatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/array-flatten": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
- },
- "node_modules/binary-extensions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
- "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/body-parser": {
- "version": "1.20.3",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
- "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
- "dependencies": {
- "bytes": "3.1.2",
- "content-type": "~1.0.5",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.13.0",
- "raw-body": "2.5.2",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
- "dependencies": {
- "fill-range": "^7.1.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/call-bind-apply-helpers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
- "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/call-bound": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
- "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "get-intrinsic": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/chokidar": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
- "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
- "dev": true,
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
- "engines": {
- "node": ">= 8.10.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "node_modules/content-disposition": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
- "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
- "dependencies": {
- "safe-buffer": "5.2.1"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/content-type": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
- "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/cookie": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
- "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/cookie-signature": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
- "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
- },
- "node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/depd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/destroy": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
- "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/dunder-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
- "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
- "es-errors": "^1.3.0",
- "gopd": "^1.2.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
- },
- "node_modules/encodeurl": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
- "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/es-define-property": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
- "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-errors": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
- "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-object-atoms": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
- "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
- "dependencies": {
- "es-errors": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
- },
- "node_modules/etag": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/express": {
- "version": "4.21.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
- "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
- "dependencies": {
- "accepts": "~1.3.8",
- "array-flatten": "1.1.1",
- "body-parser": "1.20.3",
- "content-disposition": "0.5.4",
- "content-type": "~1.0.4",
- "cookie": "0.7.1",
- "cookie-signature": "1.0.6",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "encodeurl": "~2.0.0",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "finalhandler": "1.3.1",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "merge-descriptors": "1.0.3",
- "methods": "~1.1.2",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "path-to-regexp": "0.1.12",
- "proxy-addr": "~2.0.7",
- "qs": "6.13.0",
- "range-parser": "~1.2.1",
- "safe-buffer": "5.2.1",
- "send": "0.19.0",
- "serve-static": "1.16.2",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "type-is": "~1.6.18",
- "utils-merge": "1.0.1",
- "vary": "~1.1.2"
- },
- "engines": {
- "node": ">= 0.10.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
- "node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/finalhandler": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
- "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
- "dependencies": {
- "debug": "2.6.9",
- "encodeurl": "~2.0.0",
- "escape-html": "~1.0.3",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "statuses": "2.0.1",
- "unpipe": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/forwarded": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
- "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/fresh": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
- "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "es-define-property": "^1.0.1",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.1.1",
- "function-bind": "^1.1.2",
- "get-proto": "^1.0.1",
- "gopd": "^1.2.0",
- "has-symbols": "^1.1.0",
- "hasown": "^2.0.2",
- "math-intrinsics": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
- "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
- "dependencies": {
- "dunder-proto": "^1.0.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/gopd": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
- "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
- "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/hasown": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
- "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/http-errors": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
- "dependencies": {
- "depd": "2.0.0",
- "inherits": "2.0.4",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "toidentifier": "1.0.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/ignore-by-default": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
- "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
- "dev": true
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "node_modules/ipaddr.js": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
- "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/math-intrinsics": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
- "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/media-typer": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/merge-descriptors": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
- "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/methods": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
- "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
- "bin": {
- "mime": "cli.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "node_modules/negotiator": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
- "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/nodemon": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
- "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==",
- "dev": true,
- "dependencies": {
- "chokidar": "^3.5.2",
- "debug": "^4",
- "ignore-by-default": "^1.0.1",
- "minimatch": "^3.1.2",
- "pstree.remy": "^1.1.8",
- "semver": "^7.5.3",
- "simple-update-notifier": "^2.0.0",
- "supports-color": "^5.5.0",
- "touch": "^3.1.0",
- "undefsafe": "^2.0.5"
- },
- "bin": {
- "nodemon": "bin/nodemon.js"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/nodemon"
- }
- },
- "node_modules/nodemon/node_modules/debug": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
- "dev": true,
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/nodemon/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.13.4",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
- "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/on-finished": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
- "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
- "dependencies": {
- "ee-first": "1.1.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/parseurl": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/path-to-regexp": {
- "version": "0.1.12",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
- "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/proxy-addr": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
- "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
- "dependencies": {
- "forwarded": "0.2.0",
- "ipaddr.js": "1.9.1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/pstree.remy": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
- "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
- "dev": true
- },
- "node_modules/qs": {
- "version": "6.13.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
- "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
- "dependencies": {
- "side-channel": "^1.0.6"
- },
- "engines": {
- "node": ">=0.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/range-parser": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/raw-body": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
- "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
- "dependencies": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "node_modules/semver": {
- "version": "7.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
- "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/send": {
- "version": "0.19.0",
- "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
- "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
- "dependencies": {
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "mime": "1.6.0",
- "ms": "2.1.3",
- "on-finished": "2.4.1",
- "range-parser": "~1.2.1",
- "statuses": "2.0.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/send/node_modules/encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/send/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- },
- "node_modules/serve-static": {
- "version": "1.16.2",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
- "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
- "dependencies": {
- "encodeurl": "~2.0.0",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.3",
- "send": "0.19.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/setprototypeof": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
- },
- "node_modules/side-channel": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
- "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
- "dependencies": {
- "es-errors": "^1.3.0",
- "object-inspect": "^1.13.3",
- "side-channel-list": "^1.0.0",
- "side-channel-map": "^1.0.1",
- "side-channel-weakmap": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/side-channel-list": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
- "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
- "dependencies": {
- "es-errors": "^1.3.0",
- "object-inspect": "^1.13.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/side-channel-map": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
- "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
- "dependencies": {
- "call-bound": "^1.0.2",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.5",
- "object-inspect": "^1.13.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/side-channel-weakmap": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
- "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
- "dependencies": {
- "call-bound": "^1.0.2",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.5",
- "object-inspect": "^1.13.3",
- "side-channel-map": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/simple-update-notifier": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
- "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
- "dev": true,
- "dependencies": {
- "semver": "^7.5.3"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/statuses": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/toidentifier": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
- "engines": {
- "node": ">=0.6"
- }
- },
- "node_modules/touch": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
- "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
- "dev": true,
- "bin": {
- "nodetouch": "bin/nodetouch.js"
- }
- },
- "node_modules/type-is": {
- "version": "1.6.18",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
- "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
- "dependencies": {
- "media-typer": "0.3.0",
- "mime-types": "~2.1.24"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/undefsafe": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
- "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
- "dev": true
- },
- "node_modules/unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/utils-merge": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
- "engines": {
- "node": ">= 0.8"
- }
- }
- }
-}
diff --git a/package.json b/package.json
deleted file mode 100644
index d6186ff..0000000
--- a/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "wplace-autobot-server",
- "version": "1.0.0",
- "description": "Local server for hosting WPlace AutoBOT files per branch",
- "main": "server.js",
- "scripts": {
- "start": "node server.js",
- "dev": "nodemon server.js"
- },
- "dependencies": {
- "express": "^4.18.2"
- },
- "devDependencies": {
- "nodemon": "^3.0.1"
- }
-}
\ No newline at end of file
From f6b0b9d1a17f479f6fa78ba212efcdd4e6b9503c Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Wed, 27 Aug 2025 23:30:03 +0200
Subject: [PATCH 05/14] add translation files for multiple languages
---
lang/en.json | 74 +++++++++++++++++++++++++++++++++++++++++++++++
lang/fr.json | 74 +++++++++++++++++++++++++++++++++++++++++++++++
lang/id.json | 74 +++++++++++++++++++++++++++++++++++++++++++++++
lang/ja.json | 76 +++++++++++++++++++++++++++++++++++++++++++++++++
lang/ko.json | 76 +++++++++++++++++++++++++++++++++++++++++++++++++
lang/pt.json | 74 +++++++++++++++++++++++++++++++++++++++++++++++
lang/ru.json | 74 +++++++++++++++++++++++++++++++++++++++++++++++
lang/tr.json | 74 +++++++++++++++++++++++++++++++++++++++++++++++
lang/uk.json | 74 +++++++++++++++++++++++++++++++++++++++++++++++
lang/vi.json | 74 +++++++++++++++++++++++++++++++++++++++++++++++
lang/zh-CN.json | 76 +++++++++++++++++++++++++++++++++++++++++++++++++
lang/zh-TW.json | 76 +++++++++++++++++++++++++++++++++++++++++++++++++
12 files changed, 896 insertions(+)
create mode 100644 lang/en.json
create mode 100644 lang/fr.json
create mode 100644 lang/id.json
create mode 100644 lang/ja.json
create mode 100644 lang/ko.json
create mode 100644 lang/pt.json
create mode 100644 lang/ru.json
create mode 100644 lang/tr.json
create mode 100644 lang/uk.json
create mode 100644 lang/vi.json
create mode 100644 lang/zh-CN.json
create mode 100644 lang/zh-TW.json
diff --git a/lang/en.json b/lang/en.json
new file mode 100644
index 0000000..c289751
--- /dev/null
+++ b/lang/en.json
@@ -0,0 +1,74 @@
+{
+ "title": "WPlace Auto-Image",
+ "toggleOverlay": "Toggle Overlay",
+ "scanColors": "Scan Colors",
+ "uploadImage": "Upload Image",
+ "resizeImage": "Resize Image",
+ "selectPosition": "Select Position",
+ "startPainting": "Start Painting",
+ "stopPainting": "Stop Painting",
+ "checkingColors": "🔍 Checking available colors...",
+ "noColorsFound": "❌ Open the color palette on the site and try again!",
+ "colorsFound": "✅ {count} available colors found. Ready to upload.",
+ "loadingImage": "🖼️ Loading image...",
+ "imageLoaded": "✅ Image loaded with {count} valid pixels",
+ "imageError": "❌ Error loading image",
+ "selectPositionAlert": "Paint the first pixel at the location where you want the art to start!",
+ "waitingPosition": "👆 Waiting for you to paint the reference pixel...",
+ "positionSet": "✅ Position set successfully!",
+ "positionTimeout": "❌ Timeout for position selection",
+ "startPaintingMsg": "🎨 Starting painting...",
+ "paintingProgress": "🧱 Progress: {painted}/{total} pixels...",
+ "noCharges": "⌛ No charges. Waiting {time}...",
+ "paintingStopped": "⏹️ Painting stopped by user",
+ "paintingComplete": "✅ Painting complete! {count} pixels painted.",
+ "paintingError": "❌ Error during painting",
+ "missingRequirements": "❌ Load an image and select a position first",
+ "progress": "Progress",
+ "pixels": "Pixels",
+ "charges": "Charges",
+ "estimatedTime": "Estimated time",
+ "initMessage": "Click 'Upload Image' to begin",
+ "waitingInit": "Waiting for initialization...",
+ "initializingToken": "🔧 Initializing Turnstile token generator...",
+ "tokenReady": "✅ Token generator ready - you can now start painting!",
+ "tokenRetryLater": "⚠️ Token generator will retry when needed",
+ "resizeSuccess": "✅ Image resized to {width}x{height}",
+ "paintingPaused": "⏸️ Painting paused at position X: {x}, Y: {y}",
+ "captchaNeeded": "❗ Token generation failed. Please try again in a moment.",
+ "saveData": "Save Progress",
+ "loadData": "Load Progress",
+ "saveToFile": "Save to File",
+ "loadFromFile": "Load from File",
+ "dataManager": "Data Manager",
+ "autoSaved": "✅ Progress saved automatically",
+ "dataLoaded": "✅ Progress loaded successfully",
+ "fileSaved": "✅ Progress saved to file successfully",
+ "fileLoaded": "✅ Progress loaded from file successfully",
+ "noSavedData": "❌ No saved progress found",
+ "savedDataFound": "✅ Saved progress found! Load to continue?",
+ "savedDate": "Saved on: {date}",
+ "clickLoadToContinue": "Click 'Load Progress' to continue.",
+ "fileError": "❌ Error processing file",
+ "invalidFileFormat": "❌ Invalid file format",
+ "paintingSpeed": "Painting Speed",
+ "pixelsPerSecond": "pixels/second",
+ "speedSetting": "Speed: {speed} pixels/sec",
+ "settings": "Settings",
+ "botSettings": "Bot Settings",
+ "close": "Close",
+ "language": "Language",
+ "themeSettings": "Theme Settings",
+ "themeSettingsDesc": "Choose your preferred color theme for the interface.",
+ "languageSelectDesc": "Select your preferred language. Changes will take effect immediately.",
+ "autoCaptcha": "Auto-CAPTCHA Solver (Turnstile)",
+ "autoCaptchaDesc": "Automatically generates Turnstile tokens using integrated generator. Falls back to browser automation if needed.",
+ "applySettings": "Apply Settings",
+ "settingsSaved": "✅ Settings saved successfully!",
+ "cooldownSettings": "Cooldown Settings",
+ "waitCharges": "Wait until charges reach",
+ "captchaSolving": "🔑 Generating Turnstile token...",
+ "captchaFailed": "❌ Turnstile token generation failed. Trying fallback method...",
+ "automation": "Automation",
+ "noChargesThreshold": "⌛ Waiting for charges to reach {threshold}. Currently {current}. Next in {time}..."
+}
\ No newline at end of file
diff --git a/lang/fr.json b/lang/fr.json
new file mode 100644
index 0000000..dab546d
--- /dev/null
+++ b/lang/fr.json
@@ -0,0 +1,74 @@
+{
+ "title": "WPlace Auto-Image",
+ "toggleOverlay": "Toggle Overlay",
+ "scanColors": "Scanner les couleurs",
+ "uploadImage": "Télécharger l'image",
+ "resizeImage": "Redimensionner l'image",
+ "selectPosition": "Sélectionner la position",
+ "startPainting": "Commencer à peindre",
+ "stopPainting": "Arrêter de peindre",
+ "checkingColors": "🔍 Vérification des couleurs disponibles...",
+ "noColorsFound": "❌ Ouvrez la palette de couleurs sur le site et réessayez!",
+ "colorsFound": "✅ {count} couleurs trouvées. Prêt à télécharger.",
+ "loadingImage": "🖼️ Chargement de l'image...",
+ "imageLoaded": "✅ Image chargée avec {count} pixels valides",
+ "imageError": "❌ Erreur lors du chargement de l'image",
+ "selectPositionAlert": "Peignez le premier pixel à l'endroit où vous voulez que l'art commence!",
+ "waitingPosition": "👆 En attente que vous peigniez le pixel de référence...",
+ "positionSet": "✅ Position définie avec succès!",
+ "positionTimeout": "❌ Délai d'attente pour la sélection de position",
+ "startPaintingMsg": "🎨 Début de la peinture...",
+ "paintingProgress": "🧱 Progrès: {painted}/{total} pixels...",
+ "noCharges": "⌛ Aucune charge. En attente {time}...",
+ "paintingStopped": "⏹️ Peinture arrêtée par l'utilisateur",
+ "paintingComplete": "✅ Peinture terminée! {count} pixels peints.",
+ "paintingError": "❌ Erreur pendant la peinture",
+ "missingRequirements": "❌ Veuillez charger une image et sélectionner une position d'abord",
+ "progress": "Progrès",
+ "pixels": "Pixels",
+ "charges": "Charges",
+ "estimatedTime": "Temps estimé",
+ "initMessage": "Cliquez sur 'Télécharger l'image' pour commencer",
+ "waitingInit": "En attente d'initialisation...",
+ "initializingToken": "🔧 Initialisation du générateur de tokens Turnstile...",
+ "tokenReady": "✅ Générateur de tokens prêt - vous pouvez commencer à peindre!",
+ "tokenRetryLater": "⚠️ Le générateur de tokens réessaiera si nécessaire",
+ "resizeSuccess": "✅ Image redimensionnée en {width}x{height}",
+ "paintingPaused": "⏸️ Peinture en pause à la position X: {x}, Y: {y}",
+ "captchaNeeded": "❗ Échec de la génération de token. Veuillez réessayer dans un moment.",
+ "saveData": "Sauvegarder le progrès",
+ "loadData": "Charger le progrès",
+ "saveToFile": "Sauvegarder dans un fichier",
+ "loadFromFile": "Charger depuis un fichier",
+ "dataManager": "Données",
+ "autoSaved": "✅ Progrès sauvegardé automatiquement",
+ "dataLoaded": "✅ Progrès chargé avec succès",
+ "fileSaved": "✅ Sauvegardé dans un fichier avec succès",
+ "fileLoaded": "✅ Chargé depuis un fichier avec succès",
+ "noSavedData": "❌ Aucun progrès sauvegardé trouvé",
+ "savedDataFound": "✅ Progrès sauvegardé trouvé! Charger pour continuer?",
+ "savedDate": "Sauvegardé le: {date}",
+ "clickLoadToContinue": "Cliquez sur 'Charger le progrès' pour continuer.",
+ "fileError": "❌ Erreur lors du traitement du fichier",
+ "invalidFileFormat": "❌ Format de fichier invalide",
+ "paintingSpeed": "Vitesse de peinture",
+ "pixelsPerSecond": "pixels/seconde",
+ "speedSetting": "Vitesse: {speed} pixels/sec",
+ "settings": "Paramètres",
+ "botSettings": "Paramètres du Bot",
+ "close": "Fermer",
+ "language": "Langue",
+ "themeSettings": "Paramètres de Thème",
+ "themeSettingsDesc": "Choisissez votre thème de couleurs préféré pour l'interface.",
+ "languageSelectDesc": "Sélectionnez votre langue préférée. Les changements prendront effet immédiatement.",
+ "autoCaptcha": "Résolveur de CAPTCHA automatique",
+ "autoCaptchaDesc": "Tente automatiquement de résoudre le CAPTCHA en simulant un placement manuel de pixel lorsque le jeton expire.",
+ "applySettings": "Appliquer les paramètres",
+ "settingsSaved": "✅ Paramètres enregistrés avec succès !",
+ "cooldownSettings": "Paramètres de recharge",
+ "waitCharges": "Attendre que les charges atteignent",
+ "captchaSolving": "🤖 Tentative de résolution du CAPTCHA...",
+ "captchaFailed": "❌ Échec de l'Auto-CAPTCHA. Peignez un pixel manuellement.",
+ "automation": "Automatisation",
+ "noChargesThreshold": "⌛ En attente que les charges atteignent {threshold}. Actuel: {current}. Prochaine dans {time}..."
+}
\ No newline at end of file
diff --git a/lang/id.json b/lang/id.json
new file mode 100644
index 0000000..c4332d1
--- /dev/null
+++ b/lang/id.json
@@ -0,0 +1,74 @@
+{
+ "title": "WPlace Auto-Image",
+ "toggleOverlay": "Toggle Overlay",
+ "scanColors": "Pindai Warna",
+ "uploadImage": "Unggah Gambar",
+ "resizeImage": "Ubah Ukuran Gambar",
+ "selectPosition": "Pilih Posisi",
+ "startPainting": "Mulai Melukis",
+ "stopPainting": "Berhenti Melukis",
+ "checkingColors": "🔍 Memeriksa warna yang tersedia...",
+ "noColorsFound": "❌ Buka palet warna di situs dan coba lagi!",
+ "colorsFound": "✅ {count} warna ditemukan. Siap untuk diunggah.",
+ "loadingImage": "🖼️ Memuat gambar...",
+ "imageLoaded": "✅ Gambar dimuat dengan {count} piksel valid",
+ "imageError": "❌ Kesalahan saat memuat gambar",
+ "selectPositionAlert": "Lukis piksel pertama di lokasi tempat karya seni akan dimulai!",
+ "waitingPosition": "👆 Menunggu Anda melukis piksel referensi...",
+ "positionSet": "✅ Posisi berhasil diatur!",
+ "positionTimeout": "❌ Waktu habis untuk memilih posisi",
+ "startPaintingMsg": "🎨 Mulai melukis...",
+ "paintingProgress": "🧱 Progres: {painted}/{total} piksel...",
+ "noCharges": "⌛ Tidak ada muatan. Menunggu {time}...",
+ "paintingStopped": "⏹️ Melukis dihentikan oleh pengguna",
+ "paintingComplete": "✅ Melukis selesai! {count} piksel telah dilukis.",
+ "paintingError": "❌ Kesalahan selama melukis",
+ "missingRequirements": "❌ Unggah gambar dan pilih posisi terlebih dahulu",
+ "progress": "Progres",
+ "pixels": "Piksel",
+ "charges": "Muatan",
+ "estimatedTime": "Perkiraan waktu",
+ "initMessage": "Klik 'Unggah Gambar' untuk memulai",
+ "waitingInit": "Menunggu inisialisasi...",
+ "initializingToken": "🔧 Menginisialisasi generator token Turnstile...",
+ "tokenReady": "✅ Generator token siap - Anda bisa mulai melukis!",
+ "tokenRetryLater": "⚠️ Generator token akan mencoba lagi saat diperlukan",
+ "resizeSuccess": "✅ Gambar berhasil diubah ukurannya menjadi {width}x{height}",
+ "paintingPaused": "⏸️ Melukis dijeda di posisi X: {x}, Y: {y}",
+ "captchaNeeded": "❗ Pembuatan token gagal. Silakan coba lagi sebentar lagi.",
+ "saveData": "Simpan Progres",
+ "loadData": "Muat Progres",
+ "saveToFile": "Simpan ke File",
+ "loadFromFile": "Muat dari File",
+ "dataManager": "Data",
+ "autoSaved": "✅ Progres disimpan secara otomatis",
+ "dataLoaded": "✅ Progres berhasil dimuat",
+ "fileSaved": "✅ Berhasil disimpan ke file",
+ "fileLoaded": "✅ Berhasil dimuat dari file",
+ "noSavedData": "❌ Tidak ditemukan progres yang disimpan",
+ "savedDataFound": "✅ Progres yang disimpan ditemukan! Muat untuk melanjutkan?",
+ "savedDate": "Disimpan pada: {date}",
+ "clickLoadToContinue": "Klik 'Muat Progres' untuk melanjutkan.",
+ "fileError": "❌ Kesalahan saat memproses file",
+ "invalidFileFormat": "❌ Format file tidak valid",
+ "paintingSpeed": "Kecepatan Melukis",
+ "pixelsPerSecond": "piksel/detik",
+ "speedSetting": "Kecepatan: {speed} piksel/detik",
+ "settings": "Pengaturan",
+ "botSettings": "Pengaturan Bot",
+ "close": "Tutup",
+ "language": "Bahasa",
+ "themeSettings": "Pengaturan Tema",
+ "themeSettingsDesc": "Pilih tema warna favorit Anda untuk antarmuka.",
+ "languageSelectDesc": "Pilih bahasa yang Anda inginkan. Perubahan akan berlaku segera.",
+ "autoCaptcha": "Penyelesai CAPTCHA Otomatis",
+ "autoCaptchaDesc": "Mencoba menyelesaikan CAPTCHA secara otomatis dengan mensimulasikan penempatan piksel manual saat token kedaluwarsa.",
+ "applySettings": "Terapkan Pengaturan",
+ "settingsSaved": "✅ Pengaturan berhasil disimpan!",
+ "cooldownSettings": "Pengaturan Cooldown",
+ "waitCharges": "Tunggu hingga muatan mencapai",
+ "captchaSolving": "🤖 Mencoba menyelesaikan CAPTCHA...",
+ "captchaFailed": "❌ Gagal menyelesaikan CAPTCHA. Lukis satu piksel secara manual.",
+ "automation": "Automasi",
+ "noChargesThreshold": "⌛ Menunggu muatan mencapai {threshold}. Saat ini: {current}. Berikutnya dalam {time}..."
+}
\ No newline at end of file
diff --git a/lang/ja.json b/lang/ja.json
new file mode 100644
index 0000000..ad5dfe5
--- /dev/null
+++ b/lang/ja.json
@@ -0,0 +1,76 @@
+{
+ "title": "WPlace 自動画像",
+ "toggleOverlay": "オーバーレイ切替",
+ "scanColors": "色をスキャン",
+ "uploadImage": "画像をアップロード",
+ "resizeImage": "画像サイズ変更",
+ "selectPosition": "位置を選択",
+ "startPainting": "描画開始",
+ "stopPainting": "描画停止",
+ "checkingColors": "🔍 利用可能な色を確認中...",
+ "noColorsFound": "❌ サイトでカラーパレットを開いて再試行してください!",
+ "colorsFound": "✅ 利用可能な色 {count} 件を検出。アップロード可能。",
+ "loadingImage": "🖼️ 画像を読み込み中...",
+ "imageLoaded": "✅ 画像を読み込みました。有効なピクセル {count}",
+ "imageError": "❌ 画像の読み込みエラー",
+ "selectPositionAlert": "作品を開始したい位置に最初のピクセルを置いてください!",
+ "waitingPosition": "👆 参照ピクセルの描画を待っています...",
+ "positionSet": "✅ 位置を設定しました!",
+ "positionTimeout": "❌ 位置選択のタイムアウト",
+ "startPaintingMsg": "🎨 描画を開始...",
+ "paintingProgress": "🧱 進捗: {painted}/{total} ピクセル...",
+ "noCharges": "⌛ チャージなし。{time} 待機...",
+ "paintingStopped": "⏹️ ユーザーにより停止されました",
+ "paintingComplete": "✅ 描画完了! {count} ピクセル描画。",
+ "paintingError": "❌ 描画中にエラー",
+ "missingRequirements": "❌ 先に画像を読み込み位置を選択してください",
+ "progress": "進捗",
+ "pixels": "ピクセル",
+ "charges": "チャージ",
+ "estimatedTime": "推定時間",
+ "initMessage": "「画像をアップロード」をクリックして開始",
+ "waitingInit": "初期化待機中...",
+ "initializingToken": "🔧 Turnstile トークン生成器を初期化中...",
+ "tokenReady": "✅ トークン生成器準備完了 - 描画できます!",
+ "tokenRetryLater": "⚠️ 必要に応じて再試行します",
+ "resizeSuccess": "✅ 画像を {width}x{height} にリサイズ",
+ "paintingPaused": "⏸️ X: {x}, Y: {y} で一時停止",
+ "captchaNeeded": "❗ トークン生成に失敗。少ししてから再試行してください。",
+ "saveData": "進捗を保存",
+ "loadData": "進捗を読み込み",
+ "saveToFile": "ファイルへ保存",
+ "loadFromFile": "ファイルから読み込み",
+ "dataManager": "データ管理",
+ "autoSaved": "✅ 自動保存しました",
+ "dataLoaded": "✅ 進捗を読み込みました",
+ "fileSaved": "✅ ファイルに保存しました",
+ "fileLoaded": "✅ ファイルから読み込みました",
+ "noSavedData": "❌ 保存された進捗がありません",
+ "savedDataFound": "✅ 保存された進捗が見つかりました。続行しますか?",
+ "savedDate": "保存日時: {date}",
+ "clickLoadToContinue": "「進捗を読み込み」をクリックして続行。",
+ "fileError": "❌ ファイル処理エラー",
+ "invalidFileFormat": "❌ 無効なファイル形式",
+ "paintingSpeed": "描画速度",
+ "pixelsPerSecond": "ピクセル/秒",
+ "speedSetting": "速度: {speed} ピクセル/秒",
+ "settings": "設定",
+ "botSettings": "ボット設定",
+ "close": "閉じる",
+ "language": "言語",
+ "themeSettings": "テーマ設定",
+ "themeSettingsDesc": "インターフェースの好きなカラーテーマを選択。",
+ "languageSelectDesc": "希望言語を選択。変更は即時反映されます。",
+ "autoCaptcha": "自動 CAPTCHA ソルバー",
+ "autoCaptchaDesc": "統合ジェネレーターで Turnstile トークンを自動生成し必要に応じてブラウザ自動化にフォールバック。",
+ "applySettings": "設定を適用",
+ "settingsSaved": "✅ 設定を保存しました!",
+ "speedOn": "オン",
+ "speedOff": "オフ",
+ "cooldownSettings": "クールダウン設定",
+ "waitCharges": "チャージ数が次に達するまで待機",
+ "captchaSolving": "🔑 Turnstile トークン生成中...",
+ "captchaFailed": "❌ トークン生成失敗。フォールバックを試行...",
+ "automation": "自動化",
+ "noChargesThreshold": "⌛ チャージ {threshold} を待機中。現在 {current}。次は {time} 後..."
+}
\ No newline at end of file
diff --git a/lang/ko.json b/lang/ko.json
new file mode 100644
index 0000000..4d2ac27
--- /dev/null
+++ b/lang/ko.json
@@ -0,0 +1,76 @@
+{
+ "title": "WPlace 자동 이미지",
+ "toggleOverlay": "오버레이 전환",
+ "scanColors": "색상 스캔",
+ "uploadImage": "이미지 업로드",
+ "resizeImage": "크기 조정",
+ "selectPosition": "위치 선택",
+ "startPainting": "그리기 시작",
+ "stopPainting": "그리기 중지",
+ "checkingColors": "🔍 사용 가능한 색상 확인 중...",
+ "noColorsFound": "❌ 사이트에서 색상 팔레트를 연 후 다시 시도하세요!",
+ "colorsFound": "✅ 사용 가능한 색상 {count}개 발견. 업로드 준비 완료.",
+ "loadingImage": "🖼️ 이미지 불러오는 중...",
+ "imageLoaded": "✅ 이미지 로드 완료. 유효 픽셀 {count}개",
+ "imageError": "❌ 이미지 로드 오류",
+ "selectPositionAlert": "작품을 시작할 위치에 첫 픽셀을 칠하세요!",
+ "waitingPosition": "👆 기준 픽셀을 칠할 때까지 대기 중...",
+ "positionSet": "✅ 위치 설정 완료!",
+ "positionTimeout": "❌ 위치 선택 시간 초과",
+ "startPaintingMsg": "🎨 그리기 시작...",
+ "paintingProgress": "🧱 진행: {painted}/{total} 픽셀...",
+ "noCharges": "⌛ 사용 가능 횟수 없음. {time} 대기...",
+ "paintingStopped": "⏹️ 사용자에 의해 중지됨",
+ "paintingComplete": "✅ 그리기 완료! {count} 픽셀 그렸습니다.",
+ "paintingError": "❌ 그리는 중 오류",
+ "missingRequirements": "❌ 먼저 이미지를 불러오고 위치를 선택하세요",
+ "progress": "진행",
+ "pixels": "픽셀",
+ "charges": "횟수",
+ "estimatedTime": "예상 시간",
+ "initMessage": "'이미지 업로드'를 클릭하여 시작",
+ "waitingInit": "초기화 대기 중...",
+ "initializingToken": "🔧 Turnstile 토큰 생성기 초기화 중...",
+ "tokenReady": "✅ 토큰 생성 준비 완료 - 그리기를 시작할 수 있습니다!",
+ "tokenRetryLater": "⚠️ 필요 시 다시 시도합니다",
+ "resizeSuccess": "✅ 이미지가 {width}x{height} 크기로 조정됨",
+ "paintingPaused": "⏸️ 위치 X: {x}, Y: {y} 에서 일시 중지",
+ "captchaNeeded": "❗ 토큰 생성 실패. 잠시 후 다시 시도하세요.",
+ "saveData": "진행 저장",
+ "loadData": "진행 불러오기",
+ "saveToFile": "파일로 저장",
+ "loadFromFile": "파일에서 불러오기",
+ "dataManager": "데이터",
+ "autoSaved": "✅ 진행 자동 저장됨",
+ "dataLoaded": "✅ 진행 불러오기 성공",
+ "fileSaved": "✅ 파일 저장 성공",
+ "fileLoaded": "✅ 파일 불러오기 성공",
+ "noSavedData": "❌ 저장된 진행 없음",
+ "savedDataFound": "✅ 저장된 진행 발견! 계속하려면 불러오시겠습니까?",
+ "savedDate": "저장 시각: {date}",
+ "clickLoadToContinue": "'진행 불러오기'를 클릭하여 계속.",
+ "fileError": "❌ 파일 처리 오류",
+ "invalidFileFormat": "❌ 잘못된 파일 형식",
+ "paintingSpeed": "그리기 속도",
+ "pixelsPerSecond": "픽셀/초",
+ "speedSetting": "속도: {speed} 픽셀/초",
+ "settings": "설정",
+ "botSettings": "봇 설정",
+ "close": "닫기",
+ "language": "언어",
+ "themeSettings": "테마 설정",
+ "themeSettingsDesc": "인터페이스용 선호 색상 테마를 선택하세요.",
+ "languageSelectDesc": "선호 언어를 선택하세요. 변경 사항은 즉시 적용됩니다.",
+ "autoCaptcha": "자동 CAPTCHA 해결",
+ "autoCaptchaDesc": "통합 생성기를 사용해 Turnstile 토큰을 자동 생성하고 필요 시 브라우저 자동화로 폴백.",
+ "applySettings": "설정 적용",
+ "settingsSaved": "✅ 설정 저장 완료!",
+ "speedOn": "켜짐",
+ "speedOff": "꺼짐",
+ "cooldownSettings": "쿨다운 설정",
+ "waitCharges": "횟수가 다음 값에 도달할 때까지 대기",
+ "captchaSolving": "🔑 Turnstile 토큰 생성 중...",
+ "captchaFailed": "❌ 토큰 생성 실패. 폴백 시도...",
+ "automation": "자동화",
+ "noChargesThreshold": "⌛ 횟수가 {threshold} 에 도달할 때까지 대기 중. 현재 {current}. 다음 {time} 후..."
+}
\ No newline at end of file
diff --git a/lang/pt.json b/lang/pt.json
new file mode 100644
index 0000000..29df222
--- /dev/null
+++ b/lang/pt.json
@@ -0,0 +1,74 @@
+{
+ "title": "WPlace Auto-Image",
+ "toggleOverlay": "Toggle Overlay",
+ "scanColors": "Escanear Cores",
+ "uploadImage": "Upload da Imagem",
+ "resizeImage": "Redimensionar Imagem",
+ "selectPosition": "Selecionar Posição",
+ "startPainting": "Iniciar Pintura",
+ "stopPainting": "Parar Pintura",
+ "checkingColors": "🔍 Verificando cores disponíveis...",
+ "noColorsFound": "❌ Abra a paleta de cores no site e tente novamente!",
+ "colorsFound": "✅ {count} cores encontradas. Pronto para upload.",
+ "loadingImage": "🖼️ Carregando imagem...",
+ "imageLoaded": "✅ Imagem carregada com {count} pixels válidos",
+ "imageError": "❌ Erro ao carregar imagem",
+ "selectPositionAlert": "Pinte o primeiro pixel на localização onde deseja que a arte comece!",
+ "waitingPosition": "👆 Aguardando você pintar o pixel de referência...",
+ "positionSet": "✅ Posição definida com sucesso!",
+ "positionTimeout": "❌ Tempo esgotado para selecionar posição",
+ "startPaintingMsg": "🎨 Iniciando pintura...",
+ "paintingProgress": "🧱 Progresso: {painted}/{total} pixels...",
+ "noCharges": "⌛ Sem cargas. Aguardando {time}...",
+ "paintingStopped": "⏹️ Pintura interromпида pelo usuário",
+ "paintingComplete": "✅ Pintura concluída! {count} pixels pintados.",
+ "paintingError": "❌ Erro durante a pintura",
+ "missingRequirements": "❌ Carregue uma imagem e selecione uma posição primeiro",
+ "progress": "Progresso",
+ "pixels": "Pixels",
+ "charges": "Cargas",
+ "estimatedTime": "Tempo estimado",
+ "initMessage": "Clique em 'Upload da Imagem' para começar",
+ "waitingInit": "Aguardando inicialização...",
+ "initializingToken": "🔧 Inicializando gerador de tokens Turnstile...",
+ "tokenReady": "✅ Gerador de tokens pronto - você pode começar a pintar!",
+ "tokenRetryLater": "⚠️ Gerador de tokens tentará novamente quando necessário",
+ "resizeSuccess": "✅ Imagem redimensionada для {width}x{height}",
+ "paintingPaused": "⏸️ Pintura pausada na posição X: {x}, Y: {y}",
+ "captchaNeeded": "❗ Falha na geração de token. Tente novamente em alguns instantes.",
+ "saveData": "Salvar Progresso",
+ "loadData": "Carregar Progresso",
+ "saveToFile": "Salvar em Arquivo",
+ "loadFromFile": "Carregar de Arquivo",
+ "dataManager": "Dados",
+ "autoSaved": "✅ Progresso salvo automaticamente",
+ "dataLoaded": "✅ Progresso carregado com sucesso",
+ "fileSaved": "✅ Salvo em arquivo com sucesso",
+ "fileLoaded": "✅ Carregado de arquivo com sucesso",
+ "noSavedData": "❌ Nenhum progresso salvo encontrado",
+ "savedDataFound": "✅ Progresso salvo encontrado! Carregar para continuar?",
+ "savedDate": "Salvo em: {date}",
+ "clickLoadToContinue": "Clique em 'Carregar Progresso' para continuar.",
+ "fileError": "❌ Erro ao processar arquivo",
+ "invalidFileFormat": "❌ Formato de arquivo inválido",
+ "paintingSpeed": "Velocidade de Pintura",
+ "pixelsPerSecond": "pixels/segundo",
+ "speedSetting": "Velocidade: {speed} pixels/seg",
+ "settings": "Configurações",
+ "botSettings": "Configurações do Bot",
+ "close": "Fechar",
+ "language": "Idioma",
+ "themeSettings": "Configurações de Tema",
+ "themeSettingsDesc": "Escolha seu tema de cores preferido para a interface.",
+ "languageSelectDesc": "Selecione seu idioma preferido. As alterações terão efeito imediatamente.",
+ "autoCaptcha": "Resolvedor de CAPTCHA Automático",
+ "autoCaptchaDesc": "Tenta resolver o CAPTCHA automaticamente simulando a colocação manual de um pixel quando o token expira.",
+ "applySettings": "Aplicar Configurações",
+ "settingsSaved": "✅ Configurações salvas com sucesso!",
+ "cooldownSettings": "Configurações de Cooldown",
+ "waitCharges": "Aguardar até as cargas atingirem",
+ "captchaSolving": "🤖 Tentando resolver o CAPTCHA...",
+ "captchaFailed": "❌ Falha ao resolver CAPTCHA. Pinte um pixel manualmente.",
+ "automation": "Automação",
+ "noChargesThreshold": "⌛ Aguardando cargas atingirem {threshold}. Atual: {current}. Próxima em {time}..."
+}
\ No newline at end of file
diff --git a/lang/ru.json b/lang/ru.json
new file mode 100644
index 0000000..318d071
--- /dev/null
+++ b/lang/ru.json
@@ -0,0 +1,74 @@
+{
+ "title": "WPlace Авто-Изображение",
+ "toggleOverlay": "Toggle Overlay",
+ "scanColors": "Сканировать цвета",
+ "uploadImage": "Загрузить изображение",
+ "resizeImage": "Изменить размер изображения",
+ "selectPosition": "Выбрать позицию",
+ "startPainting": "Начать рисование",
+ "stopPainting": "Остановить рисование",
+ "checkingColors": "🔍 Проверка доступных цветов...",
+ "noColorsFound": "❌ Откройте палитру цветов на сайте и попробуйте снова!",
+ "colorsFound": "✅ Найдено доступных цветов: {count}. Готово к загрузке.",
+ "loadingImage": "🖼️ Загрузка изображения...",
+ "imageLoaded": "✅ Изображение загружено, валидных пикселей: {count}",
+ "imageError": "❌ Ошибка при загрузке изображения",
+ "selectPositionAlert": "Нарисуйте первый пиксель в месте, откуда начнётся рисунок!",
+ "waitingPosition": "👆 Ожидание, пока вы нарисуете опорный пиксель...",
+ "positionSet": "✅ Позиция успешно установлена!",
+ "positionTimeout": "❌ Время ожидания выбора позиции истекло",
+ "startPaintingMsg": "🎨 Начинаем рисование...",
+ "paintingProgress": "🧱 Прогресс: {painted}/{total} пикселей...",
+ "noCharges": "⌛ Нет зарядов. Ожидание {time}...",
+ "paintingStopped": "⏹️ Рисование остановлено пользователем",
+ "paintingComplete": "✅ Рисование завершено! Нарисовано пикселей: {count}.",
+ "paintingError": "❌ Ошибка во время рисования",
+ "missingRequirements": "❌ Сначала загрузите изображение и выберите позицию",
+ "progress": "Прогресс",
+ "pixels": "Пиксели",
+ "charges": "Заряды",
+ "estimatedTime": "Примерное время",
+ "initMessage": "Нажмите 'Загрузить изображение', чтобы начать",
+ "waitingInit": "Ожидание инициализации...",
+ "initializingToken": "🔧 Инициализация генератора Turnstile токенов...",
+ "tokenReady": "✅ Генератор токенов готов - можете начинать рисование!",
+ "tokenRetryLater": "⚠️ Генератор токенов повторит попытку при необходимости",
+ "resizeSuccess": "✅ Изображение изменено до {width}x{height}",
+ "paintingPaused": "⏸️ Рисование приостановлено на позиции X: {x}, Y: {y}",
+ "captchaNeeded": "❗ Генерация токена не удалась. Пожалуйста, попробуйте через некоторое время.",
+ "saveData": "Сохранить прогресс",
+ "loadData": "Загрузить прогресс",
+ "saveToFile": "Сохранить в файл",
+ "loadFromFile": "Загрузить из файла",
+ "dataManager": "Менеджер данных",
+ "autoSaved": "✅ Прогресс сохранён автоматически",
+ "dataLoaded": "✅ Прогресс успешно загружен",
+ "fileSaved": "✅ Прогресс успешно сохранён в файл",
+ "fileLoaded": "✅ Прогресс успешно загружен из файла",
+ "noSavedData": "❌ Сохранённый прогресс не найден",
+ "savedDataFound": "✅ Найден сохранённый прогресс! Загрузить, чтобы продолжить?",
+ "savedDate": "Сохранено: {date}",
+ "clickLoadToContinue": "Нажмите 'Загрузить прогресс', чтобы продолжить.",
+ "fileError": "❌ Ошибка при обработке файла",
+ "invalidFileFormat": "❌ Неверный формат файла",
+ "paintingSpeed": "Скорость рисования",
+ "pixelsPerSecond": "пикселей/сек",
+ "speedSetting": "Скорость: {speed} пикс./сек",
+ "settings": "Настройки",
+ "botSettings": "Настройки бота",
+ "close": "Закрыть",
+ "language": "Язык",
+ "themeSettings": "Настройки темы",
+ "themeSettingsDesc": "Выберите предпочтительную цветовую тему интерфейса.",
+ "languageSelectDesc": "Выберите предпочтительный язык. Изменения вступят в силу немедленно.",
+ "autoCaptcha": "Авто-решение CAPTCHA (Turnstile)",
+ "autoCaptchaDesc": "Автоматически генерирует Turnstile токены используя встроенный генератор. Возвращается к автоматизации браузера при необходимости.",
+ "applySettings": "Применить настройки",
+ "settingsSaved": "✅ Настройки успешно сохранены!",
+ "cooldownSettings": "Настройки перезарядки",
+ "waitCharges": "Ждать до накопления зарядов",
+ "captchaSolving": "🔑 Генерирую Turnstile токен...",
+ "captchaFailed": "❌ Не удалось сгенерировать Turnstile токен. Пробую резервный метод...",
+ "automation": "Автоматизация",
+ "noChargesThreshold": "⌛ Ожидание зарядов до {threshold}. Сейчас {current}. Следующий через {time}..."
+}
\ No newline at end of file
diff --git a/lang/tr.json b/lang/tr.json
new file mode 100644
index 0000000..e70988e
--- /dev/null
+++ b/lang/tr.json
@@ -0,0 +1,74 @@
+{
+ "title": "WPlace Otomatik-Resim",
+ "toggleOverlay": "Katmanı Aç/Kapat",
+ "scanColors": "Renkleri Tara",
+ "uploadImage": "Resim Yükle",
+ "resizeImage": "Resmi Yeniden Boyutlandır",
+ "selectPosition": "Konum Seç",
+ "startPainting": "Boyamayı Başlat",
+ "stopPainting": "Boyamayı Durdur",
+ "checkingColors": "🔍 Uygun renkler kontrol ediliyor...",
+ "noColorsFound": "❌ Sitede renk paletini açın ve tekrar deneyin!",
+ "colorsFound": "✅ {count} uygun renk bulundu. Yüklemeye hazır.",
+ "loadingImage": "🖼️ Resim yükleniyor...",
+ "imageLoaded": "✅ Resim {count} geçerli piksel ile yüklendi",
+ "imageError": "❌ Resim yüklenirken hata oluştu",
+ "selectPositionAlert": "Sanatı başlatmak istediğiniz ilk pikseli boyayın!",
+ "waitingPosition": "👆 Referans pikseli boyamanız bekleniyor...",
+ "positionSet": "✅ Konum başarıyla ayarlandı!",
+ "positionTimeout": "❌ Konum seçme süresi doldu",
+ "startPaintingMsg": "🎨 Boyama başlatılıyor...",
+ "paintingProgress": "🧱 İlerleme: {painted}/{total} piksel...",
+ "noCharges": "⌛ Yeterli hak yok. Bekleniyor {time}...",
+ "paintingStopped": "⏹️ Boyama kullanıcı tarafından durduruldu",
+ "paintingComplete": "✅ Boyama tamamlandı! {count} piksel boyandı.",
+ "paintingError": "❌ Boyama sırasında hata oluştu",
+ "missingRequirements": "❌ Önce resim yükleyip konum seçmelisiniz",
+ "progress": "İlerleme",
+ "pixels": "Pikseller",
+ "charges": "Haklar",
+ "estimatedTime": "Tahmini süre",
+ "initMessage": "Başlamak için 'Resim Yükle'ye tıklayın",
+ "waitingInit": "Başlatma bekleniyor...",
+ "initializingToken": "🔧 Initializing Turnstile token generator...",
+ "tokenReady": "✅ Token generator ready - you can now start painting!",
+ "tokenRetryLater": "⚠️ Token generator will retry when needed",
+ "resizeSuccess": "✅ Resim {width}x{height} boyutuna yeniden boyutlandırıldı",
+ "paintingPaused": "⏸️ Boyama duraklatıldı, Konum X: {x}, Y: {y}",
+ "captchaNeeded": "❗ CAPTCHA gerekli. Devam etmek için bir pikseli manuel olarak boyayın.",
+ "saveData": "İlerlemeyi Kaydet",
+ "loadData": "İlerlemeyi Yükle",
+ "saveToFile": "Dosyaya Kaydet",
+ "loadFromFile": "Dosyadan Yükle",
+ "dataManager": "Veri Yöneticisi",
+ "autoSaved": "✅ İlerleme otomatik olarak kaydedildi",
+ "dataLoaded": "✅ İlerleme başarıyla yüklendi",
+ "fileSaved": "✅ İlerleme dosyaya başarıyla kaydedildi",
+ "fileLoaded": "✅ İlerleme dosyadan başarıyla yüklendi",
+ "noSavedData": "❌ Kayıtlı ilerleme bulunamadı",
+ "savedDataFound": "✅ Kayıtlı ilerleme bulundu! Devam etmek için yükleyin.",
+ "savedDate": "Kaydedilme tarihi: {date}",
+ "clickLoadToContinue": "Devam etmek için 'İlerlemeyi Yükle'ye tıklayın.",
+ "fileError": "❌ Dosya işlenirken hata oluştu",
+ "invalidFileFormat": "❌ Geçersiz dosya formatı",
+ "paintingSpeed": "Boyama Hızı",
+ "pixelsPerSecond": "piksel/saniye",
+ "speedSetting": "Hız: {speed} piksel/sn",
+ "settings": "Ayarlar",
+ "botSettings": "Bot Ayarları",
+ "close": "Kapat",
+ "language": "Dil",
+ "themeSettings": "Tema Ayarları",
+ "themeSettingsDesc": "Arayüz için tercih ettiğiniz renk temasını seçin.",
+ "languageSelectDesc": "Tercih ettiğiniz dili seçin. Değişiklikler hemen uygulanacaktır.",
+ "autoCaptcha": "Oto-CAPTCHA Çözücü",
+ "autoCaptchaDesc": "CAPTCHA süresi dolduğunda manuel piksel yerleştirmeyi taklit ederek otomatik çözmeyi dener.",
+ "applySettings": "Ayarları Uygula",
+ "settingsSaved": "✅ Ayarlar başarıyla kaydedildi!",
+ "cooldownSettings": "Bekleme Süresi Ayarları",
+ "waitCharges": "Haklar şu seviyeye ulaşana kadar bekle",
+ "captchaSolving": "🤖 CAPTCHA çözülmeye çalışılıyor...",
+ "captchaFailed": "❌ Oto-CAPTCHA başarısız oldu. Bir pikseli manuel boyayın.",
+ "automation": "Otomasyon",
+ "noChargesThreshold": "⌛ Hakların {threshold} seviyesine ulaşması bekleniyor. Şu anda {current}. Sonraki {time} içinde..."
+}
\ No newline at end of file
diff --git a/lang/uk.json b/lang/uk.json
new file mode 100644
index 0000000..5010d49
--- /dev/null
+++ b/lang/uk.json
@@ -0,0 +1,74 @@
+{
+ "title": "WPlace Авто-Зображення",
+ "toggleOverlay": "Перемкнути оверлей",
+ "scanColors": "Сканувати кольори",
+ "uploadImage": "Завантажити зображення",
+ "resizeImage": "Змінити розмір зображення",
+ "selectPosition": "Вибрати позицію",
+ "startPainting": "Почати малювання",
+ "stopPainting": "Зупинити малювання",
+ "checkingColors": "🔍 Перевірка доступних кольорів...",
+ "noColorsFound": "❌ Відкрий палітру кольорів на сайті та спробуй ще раз!",
+ "colorsFound": "✅ Знайдено {count} доступних кольорів. Готово до завантаження.",
+ "loadingImage": "🖼️ Завантаження зображення...",
+ "imageLoaded": "✅ Зображення завантажено. Валідних пікселів: {count}",
+ "imageError": "❌ Помилка завантаження зображення",
+ "selectPositionAlert": "Намалюй перший піксель у місці, де має починатися арт!",
+ "waitingPosition": "👆 Очікування на малювання референсного пікселя...",
+ "positionSet": "✅ Позицію успішно встановлено!",
+ "positionTimeout": "❌ Час вибору позиції вичерпано",
+ "startPaintingMsg": "🎨 Початок малювання...",
+ "paintingProgress": "🧱 Прогрес: {painted}/{total} пікселів...",
+ "noCharges": "⌛ Немає зарядів. Очікування {time}...",
+ "paintingStopped": "⏹️ Малювання зупинено користувачем",
+ "paintingComplete": "✅ Малювання завершено! Намальовано {count} пікселів.",
+ "paintingError": "❌ Помилка під час малювання",
+ "missingRequirements": "❌ Спершу завантаж зображення та вибери позицію",
+ "progress": "Прогрес",
+ "pixels": "Пікселі",
+ "charges": "Заряди",
+ "estimatedTime": "Орієнтовний час",
+ "initMessage": "Натисни 'Завантажити зображення', щоб почати",
+ "waitingInit": "Очікування ініціалізації...",
+ "initializingToken": "🔧 Ініціалізація генератора токенів Turnstile...",
+ "tokenReady": "✅ Генератор токенів готовий – можна починати малювання!",
+ "tokenRetryLater": "⚠️ Генератор токенів повторить спробу за потреби",
+ "resizeSuccess": "✅ Зображення змінено до {width}x{height}",
+ "paintingPaused": "⏸️ Малювання призупинено на позиції X: {x}, Y: {y}",
+ "captchaNeeded": "❗ Не вдалося згенерувати токен. Спробуй трохи пізніше.",
+ "saveData": "Зберегти прогрес",
+ "loadData": "Завантажити прогрес",
+ "saveToFile": "Зберегти у файл",
+ "loadFromFile": "Завантажити з файлу",
+ "dataManager": "Менеджер даних",
+ "autoSaved": "✅ Прогрес збережено автоматично",
+ "dataLoaded": "✅ Прогрес успішно завантажено",
+ "fileSaved": "✅ Прогрес успішно збережено у файл",
+ "fileLoaded": "✅ Прогрес успішно завантажено з файлу",
+ "noSavedData": "❌ Не знайдено збереженого прогресу",
+ "savedDataFound": "✅ Знайдено збережений прогрес! Завантажити, щоб продовжити?",
+ "savedDate": "Збережено: {date}",
+ "clickLoadToContinue": "Натисни 'Завантажити прогрес', щоб продовжити.",
+ "fileError": "❌ Помилка обробки файлу",
+ "invalidFileFormat": "❌ Невірний формат файлу",
+ "paintingSpeed": "Швидкість малювання",
+ "pixelsPerSecond": "пікселів/секунда",
+ "speedSetting": "Швидкість: {speed} пікселів/сек",
+ "settings": "Налаштування",
+ "botSettings": "Налаштування бота",
+ "close": "Закрити",
+ "language": "Мова",
+ "themeSettings": "Налаштування теми",
+ "themeSettingsDesc": "Вибери бажану колірну тему для інтерфейсу.",
+ "languageSelectDesc": "Вибери бажану мову. Зміни набудуть чинності одразу.",
+ "autoCaptcha": "Авто-CAPTCHA (Turnstile)",
+ "autoCaptchaDesc": "Автоматично генерує токени Turnstile за допомогою вбудованого генератора. Використовує автоматизацію браузера у разі потреби.",
+ "applySettings": "Застосувати налаштування",
+ "settingsSaved": "✅ Налаштування успішно збережено!",
+ "cooldownSettings": "Налаштування відновлення",
+ "waitCharges": "Очікувати, доки кількість зарядів досягне",
+ "captchaSolving": "🔑 Генерація токена Turnstile...",
+ "captchaFailed": "❌ Не вдалося згенерувати токен Turnstile. Використовую запасний метод...",
+ "automation": "Автоматизація",
+ "noChargesThreshold": "⌛ Очікування, доки заряди досягнуть {threshold}. Зараз {current}. Наступне через {time}..."
+}
\ No newline at end of file
diff --git a/lang/vi.json b/lang/vi.json
new file mode 100644
index 0000000..b27b74b
--- /dev/null
+++ b/lang/vi.json
@@ -0,0 +1,74 @@
+{
+ "title": "WPlace Auto-Image",
+ "toggleOverlay": "Toggle Overlay",
+ "scanColors": "Quét màu",
+ "uploadImage": "Tải lên hình ảnh",
+ "resizeImage": "Thay đổi kích thước",
+ "selectPosition": "Chọn vị trí",
+ "startPainting": "Bắt đầu vẽ",
+ "stopPainting": "Dừng vẽ",
+ "checkingColors": "🔍 Đang kiểm tra màu sắc có sẵn...",
+ "noColorsFound": "❌ Hãy mở bảng màu trên trang web và thử lại!",
+ "colorsFound": "✅ Tìm thấy {count} màu. Sẵn sàng để tải lên.",
+ "loadingImage": "🖼️ Đang tải hình ảnh...",
+ "imageLoaded": "✅ Đã tải hình ảnh với {count} pixel hợp lệ",
+ "imageError": "❌ Lỗi khi tải hình ảnh",
+ "selectPositionAlert": "Vẽ pixel đầu tiên tại vị trí bạn muốn tác phẩm nghệ thuật bắt đầu!",
+ "waitingPosition": "👆 Đang chờ bạn vẽ pixel tham chiếu...",
+ "positionSet": "✅ Đã đặt vị trí thành công!",
+ "positionTimeout": "❌ Hết thời gian chọn vị trí",
+ "startPaintingMsg": "🎨 Bắt đầu vẽ...",
+ "paintingProgress": "🧱 Tiến trình: {painted}/{total} pixel...",
+ "noCharges": "⌛ Không có điện tích. Đang chờ {time}...",
+ "paintingStopped": "⏹️ Người dùng đã dừng vẽ",
+ "paintingComplete": "✅ Hoàn thành vẽ! Đã vẽ {count} pixel.",
+ "paintingError": "❌ Lỗi trong quá trình vẽ",
+ "missingRequirements": "❌ Hãy tải lên hình ảnh và chọn vị trí trước",
+ "progress": "Tiến trình",
+ "pixels": "Pixel",
+ "charges": "Điện tích",
+ "estimatedTime": "Thời gian ước tính",
+ "initMessage": "Nhấp 'Tải lên hình ảnh' để bắt đầu",
+ "waitingInit": "Đang chờ khởi tạo...",
+ "initializingToken": "🔧 Đang khởi tạo bộ tạo token Turnstile...",
+ "tokenReady": "✅ Bộ tạo token đã sẵn sàng - bạn có thể bắt đầu vẽ!",
+ "tokenRetryLater": "⚠️ Bộ tạo token sẽ thử lại khi cần thiết",
+ "resizeSuccess": "✅ Đã thay đổi kích thước hình ảnh thành {width}x{height}",
+ "paintingPaused": "⏸️ Tạm dừng vẽ tại vị trí X: {x}, Y: {y}",
+ "captchaNeeded": "❗ Tạo token thất bại. Vui lòng thử lại sau.",
+ "saveData": "Lưu tiến trình",
+ "loadData": "Tải tiến trình",
+ "saveToFile": "Lưu vào tệp",
+ "loadFromFile": "Tải từ tệp",
+ "dataManager": "Dữ liệu",
+ "autoSaved": "✅ Đã tự động lưu tiến trình",
+ "dataLoaded": "✅ Đã tải tiến trình thành công",
+ "fileSaved": "✅ Đã lưu vào tệp thành công",
+ "fileLoaded": "✅ Đã tải từ tệp thành công",
+ "noSavedData": "❌ Không tìm thấy tiến trình đã lưu",
+ "savedDataFound": "✅ Tìm thấy tiến trình đã lưu! Tải để tiếp tục?",
+ "savedDate": "Đã lưu vào: {date}",
+ "clickLoadToContinue": "Nhấp 'Tải tiến trình' để tiếp tục.",
+ "fileError": "❌ Lỗi khi xử lý tệp",
+ "invalidFileFormat": "❌ Định dạng tệp không hợp lệ",
+ "paintingSpeed": "Tốc độ vẽ",
+ "pixelsPerSecond": "pixel/giây",
+ "speedSetting": "Tốc độ: {speed} pixel/giây",
+ "settings": "Cài đặt",
+ "botSettings": "Cài đặt Bot",
+ "close": "Đóng",
+ "language": "Ngôn ngữ",
+ "themeSettings": "Cài đặt Giao diện",
+ "themeSettingsDesc": "Chọn chủ đề màu sắc yêu thích cho giao diện.",
+ "languageSelectDesc": "Chọn ngôn ngữ ưa thích. Thay đổi sẽ có hiệu lực ngay lập tức.",
+ "autoCaptcha": "Tự động giải CAPTCHA",
+ "autoCaptchaDesc": "Tự động cố gắng giải CAPTCHA bằng cách mô phỏng việc đặt pixel thủ công khi token hết hạn.",
+ "applySettings": "Áp dụng cài đặt",
+ "settingsSaved": "✅ Đã lưu cài đặt thành công!",
+ "cooldownSettings": "Cài đặt thời gian chờ",
+ "waitCharges": "Chờ cho đến khi số lần sạc đạt",
+ "captchaSolving": "🤖 Đang cố gắng giải CAPTCHA...",
+ "captchaFailed": "❌ Giải CAPTCHA tự động thất bại. Vui lòng vẽ một pixel thủ công.",
+ "automation": "Tự động hóa",
+ "noChargesThreshold": "⌛ Đang chờ số lần sạc đạt {threshold}. Hiện tại {current}. Lần tiếp theo trong {time}..."
+}
\ No newline at end of file
diff --git a/lang/zh-CN.json b/lang/zh-CN.json
new file mode 100644
index 0000000..7c74493
--- /dev/null
+++ b/lang/zh-CN.json
@@ -0,0 +1,76 @@
+{
+ "title": "WPlace 自动图像",
+ "toggleOverlay": "切换覆盖层",
+ "scanColors": "扫描颜色",
+ "uploadImage": "上传图像",
+ "resizeImage": "调整大小",
+ "selectPosition": "选择位置",
+ "startPainting": "开始绘制",
+ "stopPainting": "停止绘制",
+ "checkingColors": "🔍 正在检查可用颜色...",
+ "noColorsFound": "❌ 请在网站上打开调色板后再试!",
+ "colorsFound": "✅ 找到 {count} 个可用颜色,准备上传。",
+ "loadingImage": "🖼️ 正在加载图像...",
+ "imageLoaded": "✅ 图像已加载,包含 {count} 个有效像素",
+ "imageError": "❌ 加载图像时出错",
+ "selectPositionAlert": "请在你想让作品开始的位置绘制第一个像素!",
+ "waitingPosition": "👆 正在等待你绘制参考像素...",
+ "positionSet": "✅ 位置设置成功!",
+ "positionTimeout": "❌ 选择位置超时",
+ "startPaintingMsg": "🎨 开始绘制...",
+ "paintingProgress": "🧱 进度: {painted}/{total} 像素...",
+ "noCharges": "⌛ 无可用次数,等待 {time}...",
+ "paintingStopped": "⏹️ 已被用户停止",
+ "paintingComplete": "✅ 绘制完成!共绘制 {count} 个像素。",
+ "paintingError": "❌ 绘制过程中出错",
+ "missingRequirements": "❌ 请先加载图像并选择位置",
+ "progress": "进度",
+ "pixels": "像素",
+ "charges": "次数",
+ "estimatedTime": "预计时间",
+ "initMessage": "点击"上传图像"开始",
+ "waitingInit": "正在等待初始化...",
+ "initializingToken": "🔧 正在初始化 Turnstile 令牌生成器...",
+ "tokenReady": "✅ 令牌生成器已就绪 - 可以开始绘制!",
+ "tokenRetryLater": "⚠️ 令牌生成器稍后将重试",
+ "resizeSuccess": "✅ 图像已调整为 {width}x{height}",
+ "paintingPaused": "⏸️ 在位置 X: {x}, Y: {y} 暂停",
+ "captchaNeeded": "❗ 令牌生成失败,请稍后再试。",
+ "saveData": "保存进度",
+ "loadData": "加载进度",
+ "saveToFile": "保存到文件",
+ "loadFromFile": "从文件加载",
+ "dataManager": "数据管理",
+ "autoSaved": "✅ 进度已自动保存",
+ "dataLoaded": "✅ 进度加载成功",
+ "fileSaved": "✅ 已成功保存到文件",
+ "fileLoaded": "✅ 已成功从文件加载",
+ "noSavedData": "❌ 未找到已保存进度",
+ "savedDataFound": "✅ 找到已保存进度!是否加载继续?",
+ "savedDate": "保存时间: {date}",
+ "clickLoadToContinue": "点击"加载进度"继续。",
+ "fileError": "❌ 处理文件时出错",
+ "invalidFileFormat": "❌ 文件格式无效",
+ "paintingSpeed": "绘制速度",
+ "pixelsPerSecond": "像素/秒",
+ "speedSetting": "速度: {speed} 像素/秒",
+ "settings": "设置",
+ "botSettings": "机器人设置",
+ "close": "关闭",
+ "language": "语言",
+ "themeSettings": "主题设置",
+ "themeSettingsDesc": "为界面选择你喜欢的配色主题。",
+ "languageSelectDesc": "选择你偏好的语言,变更立即生效。",
+ "autoCaptcha": "自动 CAPTCHA 解决",
+ "autoCaptchaDesc": "使用集成的生成器自动生成 Turnstile 令牌,必要时回退到浏览器自动化。",
+ "applySettings": "应用设置",
+ "settingsSaved": "✅ 设置保存成功!",
+ "speedOn": "开启",
+ "speedOff": "关闭",
+ "cooldownSettings": "冷却设置",
+ "waitCharges": "等待次数达到",
+ "captchaSolving": "🔑 正在生成 Turnstile 令牌...",
+ "captchaFailed": "❌ 令牌生成失败。尝试回退方法...",
+ "automation": "自动化",
+ "noChargesThreshold": "⌛ 等待次数达到 {threshold}。当前 {current}。下次在 {time}..."
+}
\ No newline at end of file
diff --git a/lang/zh-TW.json b/lang/zh-TW.json
new file mode 100644
index 0000000..e95b440
--- /dev/null
+++ b/lang/zh-TW.json
@@ -0,0 +1,76 @@
+{
+ "title": "WPlace 自動圖像",
+ "toggleOverlay": "切換覆蓋層",
+ "scanColors": "掃描顏色",
+ "uploadImage": "上傳圖像",
+ "resizeImage": "調整大小",
+ "selectPosition": "選擇位置",
+ "startPainting": "開始繪製",
+ "stopPainting": "停止繪製",
+ "checkingColors": "🔍 正在檢查可用顏色...",
+ "noColorsFound": "❌ 請在網站上打開調色板後再試!",
+ "colorsFound": "✅ 找到 {count} 個可用顏色,準備上傳。",
+ "loadingImage": "🖼️ 正在載入圖像...",
+ "imageLoaded": "✅ 圖像已載入,包含 {count} 個有效像素",
+ "imageError": "❌ 載入圖像時出錯",
+ "selectPositionAlert": "請在你想讓作品開始的位置繪製第一個像素!",
+ "waitingPosition": "👆 正在等待你繪製參考像素...",
+ "positionSet": "✅ 位置設定成功!",
+ "positionTimeout": "❌ 選擇位置逾時",
+ "startPaintingMsg": "🎨 開始繪製...",
+ "paintingProgress": "🧱 進度: {painted}/{total} 像素...",
+ "noCharges": "⌛ 無可用次數,等待 {time}...",
+ "paintingStopped": "⏹️ 已被使用者停止",
+ "paintingComplete": "✅ 繪製完成!共繪製 {count} 個像素。",
+ "paintingError": "❌ 繪製過程中出錯",
+ "missingRequirements": "❌ 請先載入圖像並選擇位置",
+ "progress": "進度",
+ "pixels": "像素",
+ "charges": "次數",
+ "estimatedTime": "預計時間",
+ "initMessage": "點擊「上傳圖像」開始",
+ "waitingInit": "正在等待初始化...",
+ "initializingToken": "🔧 正在初始化 Turnstile 令牌產生器...",
+ "tokenReady": "✅ 令牌產生器已就緒 - 可以開始繪製!",
+ "tokenRetryLater": "⚠️ 令牌產生器稍後將重試",
+ "resizeSuccess": "✅ 圖像已調整為 {width}x{height}",
+ "paintingPaused": "⏸️ 在位置 X: {x}, Y: {y} 暫停",
+ "captchaNeeded": "❗ 令牌產生失敗,請稍後再試。",
+ "saveData": "儲存進度",
+ "loadData": "載入進度",
+ "saveToFile": "儲存至檔案",
+ "loadFromFile": "從檔案載入",
+ "dataManager": "資料管理",
+ "autoSaved": "✅ 進度已自動儲存",
+ "dataLoaded": "✅ 進度載入成功",
+ "fileSaved": "✅ 已成功儲存至檔案",
+ "fileLoaded": "✅ 已成功從檔案載入",
+ "noSavedData": "❌ 未找到已儲存進度",
+ "savedDataFound": "✅ 找到已儲存進度!是否載入以繼續?",
+ "savedDate": "儲存時間: {date}",
+ "clickLoadToContinue": "點擊「載入進度」繼續。",
+ "fileError": "❌ 處理檔案時出錯",
+ "invalidFileFormat": "❌ 檔案格式無效",
+ "paintingSpeed": "繪製速度",
+ "pixelsPerSecond": "像素/秒",
+ "speedSetting": "速度: {speed} 像素/秒",
+ "settings": "設定",
+ "botSettings": "機器人設定",
+ "close": "關閉",
+ "language": "語言",
+ "themeSettings": "主題設定",
+ "themeSettingsDesc": "為介面選擇你喜歡的配色主題。",
+ "languageSelectDesc": "選擇你偏好的語言,變更立即生效。",
+ "autoCaptcha": "自動 CAPTCHA 解決",
+ "autoCaptchaDesc": "使用整合的產生器自動產生 Turnstile 令牌,必要時回退到瀏覽器自動化。",
+ "applySettings": "套用設定",
+ "settingsSaved": "✅ 設定儲存成功!",
+ "speedOn": "開啟",
+ "speedOff": "關閉",
+ "cooldownSettings": "冷卻設定",
+ "waitCharges": "等待次數達到",
+ "captchaSolving": "🔑 正在產生 Turnstile 令牌...",
+ "captchaFailed": "❌ 令牌產生失敗。嘗試回退方法...",
+ "automation": "自動化",
+ "noChargesThreshold": "⌛ 等待次數達到 {threshold}。目前 {current}。下次在 {time}..."
+}
\ No newline at end of file
From 32b4e639e460de7b08e40803e96953907fe8af70 Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Wed, 27 Aug 2025 23:30:49 +0200
Subject: [PATCH 06/14] remove server.js artafact of me 'fooling' around
earlier
---
server.js | 182 ------------------------------------------------------
1 file changed, 182 deletions(-)
delete mode 100644 server.js
diff --git a/server.js b/server.js
deleted file mode 100644
index 5c330cb..0000000
--- a/server.js
+++ /dev/null
@@ -1,182 +0,0 @@
-const express = require('express');
-const { exec } = require('child_process');
-const fs = require('fs');
-const path = require('path');
-
-const app = express();
-const port = 3000;
-
-// Cache for branch files
-const branchCache = new Map();
-
-// Get all branches and their files
-function getBranchFiles(callback) {
- exec('git branch -r | cut -c 3- | sed "s/origin\\///g"', (error, stdout, stderr) => {
- if (error) {
- console.error('Error getting branches:', error);
- callback([]);
- return;
- }
-
- const branches = stdout.trim().split('\n').filter(branch => branch && branch !== 'HEAD');
- const branchData = [];
-
- let completed = 0;
- branches.forEach(branch => {
- exec(`git show ${branch.includes('origin/') ? branch : 'origin/' + branch}:Auto-Farm.js 2>/dev/null`, (err, farmJs) => {
- exec(`git show ${branch.includes('origin/') ? branch : 'origin/' + branch}:Auto-Image.js 2>/dev/null`, (err2, imageJs) => {
- exec(`git ls-tree -r --name-only ${branch.includes('origin/') ? branch : 'origin/' + branch} | grep -E "\\.(js|css|html|json)$" 2>/dev/null`, (err3, files) => {
- const branchFiles = {};
-
- if (!err && farmJs) branchFiles['Auto-Farm.js'] = farmJs;
- if (!err2 && imageJs) branchFiles['Auto-Image.js'] = imageJs;
-
- // Get other files
- if (!err3 && files) {
- const fileList = files.trim().split('\n').filter(f => f);
- let fileCount = fileList.length;
-
- if (fileCount === 0) {
- branchData.push({ branch, files: branchFiles });
- completed++;
- if (completed === branches.length) callback(branchData);
- return;
- }
-
- fileList.forEach(filename => {
- if (!branchFiles[path.basename(filename)]) {
- exec(`git show ${branch.includes('origin/') ? branch : 'origin/' + branch}:${filename} 2>/dev/null`, (err4, content) => {
- if (!err4 && content) {
- branchFiles[path.basename(filename)] = content;
- }
- fileCount--;
- if (fileCount === 0) {
- branchData.push({ branch, files: branchFiles });
- completed++;
- if (completed === branches.length) callback(branchData);
- }
- });
- } else {
- fileCount--;
- if (fileCount === 0) {
- branchData.push({ branch, files: branchFiles });
- completed++;
- if (completed === branches.length) callback(branchData);
- }
- }
- });
- } else {
- branchData.push({ branch, files: branchFiles });
- completed++;
- if (completed === branches.length) callback(branchData);
- }
- });
- });
- });
- });
- });
-}
-
-// Serve files per branch
-app.get('/:branch/:filename', (req, res) => {
- const { branch, filename } = req.params;
-
- getBranchFiles((branches) => {
- const branchData = branches.find(b => b.branch === branch || b.branch === `origin/${branch}`);
-
- if (!branchData || !branchData.files[filename]) {
- return res.status(404).send('File not found');
- }
-
- // Set appropriate content type
- if (filename.endsWith('.js')) {
- res.setHeader('Content-Type', 'application/javascript');
- } else if (filename.endsWith('.css')) {
- res.setHeader('Content-Type', 'text/css');
- } else if (filename.endsWith('.html')) {
- res.setHeader('Content-Type', 'text/html');
- } else if (filename.endsWith('.json')) {
- res.setHeader('Content-Type', 'application/json');
- }
-
- // Enable CORS for browser scripts
- res.setHeader('Access-Control-Allow-Origin', '*');
-
- res.send(branchData.files[filename]);
- });
-});
-
-// Serve index page
-app.get('/', (req, res) => {
- getBranchFiles((branches) => {
- let html = `
-
-
-
- WPlace AutoBOT - Local Server
-
-
-
-
-
🚀 WPlace AutoBOT - Local Server
-
Server URL: ${req.protocol}://${req.get('host')}
-
Use ngrok to expose this server: ngrok http 3000
-`;
-
- branches.forEach(branchData => {
- const branch = branchData.branch.replace('origin/', '');
- html += `
-
-
📁 Branch: ${branch}
-
-`;
- Object.keys(branchData.files).forEach(filename => {
- const url = `${req.protocol}://${req.get('host')}/${branch}/${filename}`;
- html += `
${filename} `;
-
- if (filename.endsWith('.js')) {
- html += `
-
-
- Bookmarklet for ${filename}:
- javascript:fetch("${url}").then(t=>t.text()).then(eval);
- Copy
-
-
`;
- }
- });
- html += `
`;
- });
-
- html += `
-
-
-
-
-`;
-
- res.send(html);
- });
-});
-
-app.listen(port, () => {
- console.log(`🚀 WPlace AutoBOT server running at http://localhost:${port}`);
- console.log(`📡 Run 'ngrok http ${port}' to expose this server publicly`);
- console.log(`🔗 Then use URLs like: https://abc123.ngrok.io/main/Auto-Farm.js`);
-});
\ No newline at end of file
From cfdc1ab13da5128234542d2bcc81f306994e168b Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Wed, 27 Aug 2025 23:50:41 +0200
Subject: [PATCH 07/14] refactor: enhance language loading and translation
fallback mechanism
---
Auto-Image.js | 1021 ++++++-------------------------------------------
1 file changed, 109 insertions(+), 912 deletions(-)
diff --git a/Auto-Image.js b/Auto-Image.js
index 2c97f18..3d633c7 100644
--- a/Auto-Image.js
+++ b/Auto-Image.js
@@ -211,917 +211,86 @@
}
}
- const loadLanguagePreference = () => {
+ const loadLanguagePreference = async () => {
const savedLanguage = localStorage.getItem("wplace_language")
const browserLocale = navigator.language
const browserLanguage = browserLocale.split("-")[0]
- if (TEXT[savedLanguage]) { // trying to load saved language
+ // Check if we have the saved language available
+ if (savedLanguage && AVAILABLE_LANGUAGES.includes(savedLanguage)) {
state.language = savedLanguage
- } else if (TEXT[browserLocale]) { // trying to load full locale match (e.g. "zh-CN", "zh-TW" etc)
+ await loadTranslations(savedLanguage)
+ return
+ }
+
+ // Try full locale match (e.g. "zh-CN", "zh-TW" etc)
+ if (AVAILABLE_LANGUAGES.includes(browserLocale)) {
state.language = browserLocale
localStorage.setItem("wplace_language", browserLocale)
- } else if (TEXT[browserLanguage]) { // trying to load base language match (e.g. "en" for "en-US" or "en-GB" etc)
- state.language = browserLanguage
- localStorage.setItem("wplace_language", browserLanguage)
+ await loadTranslations(browserLocale)
+ return
}
+
+ // Try base language match (e.g. "en" for "en-US" or "en-GB" etc)
+ if (AVAILABLE_LANGUAGES.includes(browserLanguage)) {
+ state.language = browserLanguage
+ localStorage.setItem("wplace_language", browserLanguage)
+ await loadTranslations(browserLanguage)
+ return
+ }
+
+ // Fallback to English
+ state.language = "en"
+ await loadTranslations("en")
}
// Simple translation cache
const translationCache = new Map();
- // BILINGUAL TEXT STRINGS (FALLBACK):)
- const TEXT = {
+ // Dynamically loaded translations
+ let loadedTranslations = {};
+
+ // Available languages
+ const AVAILABLE_LANGUAGES = ['en', 'ru', 'pt', 'vi', 'fr', 'id', 'tr', 'zh-CN', 'zh-TW', 'ja', 'ko', 'uk'];
+
+ // Function to load translations from JSON file
+ const loadTranslations = async (language) => {
+ if (loadedTranslations[language]) {
+ return loadedTranslations[language];
+ }
+
+ // Load translations from CDN
+ const url = `https://staninna.github.io/WPlace-AutoBOT/decoupled-translations/lang/${language}.json`;
+
+ try {
+ console.log(`🔄 Loading ${language} translations from CDN...`);
+ const response = await fetch(url);
+ if (response.ok) {
+ const translations = await response.json();
+ loadedTranslations[language] = translations;
+ console.log(`📚 Loaded ${language} translations successfully from CDN`);
+ return translations;
+ } else {
+ console.warn(`❌ CDN returned HTTP ${response.status}: ${response.statusText} for ${language} translations`);
+ }
+ } catch (error) {
+ console.error(`❌ Failed to load ${language} translations from CDN:`, error);
+ }
+
+ return null;
+ };
+
+ // Emergency fallback TEXT (minimal)
+ const FALLBACK_TEXT = {
en: {
title: "WPlace Auto-Image",
- toggleOverlay: "Toggle Overlay",
- scanColors: "Scan Colors",
- uploadImage: "Upload Image",
- resizeImage: "Resize Image",
- selectPosition: "Select Position",
- startPainting: "Start Painting",
- stopPainting: "Stop Painting",
- checkingColors: "🔍 Checking available colors...",
- noColorsFound: "❌ Open the color palette on the site and try again!",
- colorsFound: "✅ {count} available colors found. Ready to upload.",
- loadingImage: "🖼️ Loading image...",
- imageLoaded: "✅ Image loaded with {count} valid pixels",
- imageError: "❌ Error loading image",
- selectPositionAlert: "Paint the first pixel at the location where you want the art to start!",
- waitingPosition: "👆 Waiting for you to paint the reference pixel...",
- positionSet: "✅ Position set successfully!",
- positionTimeout: "❌ Timeout for position selection",
- startPaintingMsg: "🎨 Starting painting...",
- paintingProgress: "🧱 Progress: {painted}/{total} pixels...",
- noCharges: "⌛ No charges. Waiting {time}...",
- paintingStopped: "⏹️ Painting stopped by user",
- paintingComplete: "✅ Painting complete! {count} pixels painted.",
- paintingError: "❌ Error during painting",
- missingRequirements: "❌ Load an image and select a position first",
- progress: "Progress",
- pixels: "Pixels",
- charges: "Charges",
- estimatedTime: "Estimated time",
- initMessage: "Click 'Upload Image' to begin",
- waitingInit: "Waiting for initialization...",
- initializingToken: "🔧 Initializing Turnstile token generator...",
- tokenReady: "✅ Token generator ready - you can now start painting!",
- tokenRetryLater: "⚠️ Token generator will retry when needed",
- resizeSuccess: "✅ Image resized to {width}x{height}",
- paintingPaused: "⏸️ Painting paused at position X: {x}, Y: {y}",
- captchaNeeded: "❗ Token generation failed. Please try again in a moment.",
- saveData: "Save Progress",
- loadData: "Load Progress",
- saveToFile: "Save to File",
- loadFromFile: "Load from File",
- dataManager: "Data Manager",
- autoSaved: "✅ Progress saved automatically",
- dataLoaded: "✅ Progress loaded successfully",
- fileSaved: "✅ Progress saved to file successfully",
- fileLoaded: "✅ Progress loaded from file successfully",
- noSavedData: "❌ No saved progress found",
- savedDataFound: "✅ Saved progress found! Load to continue?",
- savedDate: "Saved on: {date}",
- clickLoadToContinue: "Click 'Load Progress' to continue.",
- fileError: "❌ Error processing file",
- invalidFileFormat: "❌ Invalid file format",
- paintingSpeed: "Painting Speed",
- pixelsPerSecond: "pixels/second",
- speedSetting: "Speed: {speed} pixels/sec",
- settings: "Settings",
- botSettings: "Bot Settings",
+ settings: "Settings",
close: "Close",
language: "Language",
- themeSettings: "Theme Settings",
- themeSettingsDesc: "Choose your preferred color theme for the interface.",
- languageSelectDesc: "Select your preferred language. Changes will take effect immediately.",
- autoCaptcha: "Auto-CAPTCHA Solver (Turnstile)",
- autoCaptchaDesc: "Automatically generates Turnstile tokens using integrated generator. Falls back to browser automation if needed.",
- applySettings: "Apply Settings",
- settingsSaved: "✅ Settings saved successfully!",
- cooldownSettings: "Cooldown Settings",
- waitCharges: "Wait until charges reach",
- captchaSolving: "🔑 Generating Turnstile token...",
- captchaFailed: "❌ Turnstile token generation failed. Trying fallback method...",
- automation: "Automation",
- noChargesThreshold: "⌛ Waiting for charges to reach {threshold}. Currently {current}. Next in {time}...",
- },
- ru: {
- title: "WPlace Авто-Изображение",
- scanColors: "Сканировать цвета",
- uploadImage: "Загрузить изображение",
- resizeImage: "Изменить размер изображения",
- selectPosition: "Выбрать позицию",
- startPainting: "Начать рисование",
- stopPainting: "Остановить рисование",
- checkingColors: "🔍 Проверка доступных цветов...",
- noColorsFound: "❌ Откройте палитру цветов на сайте и попробуйте снова!",
- colorsFound: "✅ Найдено доступных цветов: {count}. Готово к загрузке.",
- loadingImage: "🖼️ Загрузка изображения...",
- imageLoaded: "✅ Изображение загружено, валидных пикселей: {count}",
- imageError: "❌ Ошибка при загрузке изображения",
- selectPositionAlert: "Нарисуйте первый пиксель в месте, откуда начнётся рисунок!",
- waitingPosition: "👆 Ожидание, пока вы нарисуете опорный пиксель...",
- positionSet: "✅ Позиция успешно установлена!",
- positionTimeout: "❌ Время ожидания выбора позиции истекло",
- startPaintingMsg: "🎨 Начинаем рисование...",
- paintingProgress: "🧱 Прогресс: {painted}/{total} пикселей...",
- noCharges: "⌛ Нет зарядов. Ожидание {time}...",
- paintingStopped: "⏹️ Рисование остановлено пользователем",
- paintingComplete: "✅ Рисование завершено! Нарисовано пикселей: {count}.",
- paintingError: "❌ Ошибка во время рисования",
- missingRequirements: "❌ Сначала загрузите изображение и выберите позицию",
- progress: "Прогресс",
- pixels: "Пиксели",
- charges: "Заряды",
- estimatedTime: "Примерное время",
- initMessage: "Нажмите 'Загрузить изображение', чтобы начать",
- waitingInit: "Ожидание инициализации...",
- initializingToken: "🔧 Инициализация генератора Turnstile токенов...",
- tokenReady: "✅ Генератор токенов готов - можете начинать рисование!",
- tokenRetryLater: "⚠️ Генератор токенов повторит попытку при необходимости",
- resizeSuccess: "✅ Изображение изменено до {width}x{height}",
- paintingPaused: "⏸️ Рисование приостановлено на позиции X: {x}, Y: {y}",
- captchaNeeded: "❗ Генерация токена не удалась. Пожалуйста, попробуйте через некоторое время.",
- saveData: "Сохранить прогресс",
- loadData: "Загрузить прогресс",
- saveToFile: "Сохранить в файл",
- loadFromFile: "Загрузить из файла",
- dataManager: "Менеджер данных",
- autoSaved: "✅ Прогресс сохранён автоматически",
- dataLoaded: "✅ Прогресс успешно загружен",
- fileSaved: "✅ Прогресс успешно сохранён в файл",
- fileLoaded: "✅ Прогресс успешно загружен из файла",
- noSavedData: "❌ Сохранённый прогресс не найден",
- savedDataFound: "✅ Найден сохранённый прогресс! Загрузить, чтобы продолжить?",
- savedDate: "Сохранено: {date}",
- clickLoadToContinue: "Нажмите 'Загрузить прогресс', чтобы продолжить.",
- fileError: "❌ Ошибка при обработке файла",
- invalidFileFormat: "❌ Неверный формат файла",
- paintingSpeed: "Скорость рисования",
- pixelsPerSecond: "пикселей/сек",
- speedSetting: "Скорость: {speed} пикс./сек",
- settings: "Настройки",
- botSettings: "Настройки бота",
- close: "Закрыть",
- language: "Язык",
- themeSettings: "Настройки темы",
- themeSettingsDesc: "Выберите предпочтительную цветовую тему интерфейса.",
- languageSelectDesc: "Выберите предпочтительный язык. Изменения вступят в силу немедленно.",
- autoCaptcha: "Авто-решение CAPTCHA (Turnstile)",
- autoCaptchaDesc: "Автоматически генерирует Turnstile токены используя встроенный генератор. Возвращается к автоматизации браузера при необходимости.",
- applySettings: "Применить настройки",
- settingsSaved: "✅ Настройки успешно сохранены!",
- cooldownSettings: "Настройки перезарядки",
- waitCharges: "Ждать до накопления зарядов",
- captchaSolving: "🔑 Генерирую Turnstile токен...",
- captchaFailed: "❌ Не удалось сгенерировать Turnstile токен. Пробую резервный метод...",
- automation: "Автоматизация",
- noChargesThreshold: "⌛ Ожидание зарядов до {threshold}. Сейчас {current}. Следующий через {time}...",
- },
- pt: {
- title: "WPlace Auto-Image",
- scanColors: "Escanear Cores",
- uploadImage: "Upload da Imagem",
- resizeImage: "Redimensionar Imagem",
- selectPosition: "Selecionar Posição",
- startPainting: "Iniciar Pintura",
- stopPainting: "Parar Pintura",
- checkingColors: "🔍 Verificando cores disponíveis...",
- noColorsFound: "❌ Abra a paleta de cores no site e tente novamente!",
- colorsFound: "✅ {count} cores encontradas. Pronto para upload.",
- loadingImage: "🖼️ Carregando imagem...",
- imageLoaded: "✅ Imagem carregada com {count} pixels válidos",
- imageError: "❌ Erro ao carregar imagem",
- selectPositionAlert: "Pinte o primeiro pixel на localização onde deseja que a arte comece!",
- waitingPosition: "👆 Aguardando você pintar o pixel de referência...",
- positionSet: "✅ Posição definida com sucesso!",
- positionTimeout: "❌ Tempo esgotado para selecionar posição",
- startPaintingMsg: "🎨 Iniciando pintura...",
- paintingProgress: "🧱 Progresso: {painted}/{total} pixels...",
- noCharges: "⌛ Sem cargas. Aguardando {time}...",
- paintingStopped: "⏹️ Pintura interromпида pelo usuário",
- paintingComplete: "✅ Pintura concluída! {count} pixels pintados.",
- paintingError: "❌ Erro durante a pintura",
- missingRequirements: "❌ Carregue uma imagem e selecione uma posição primeiro",
- progress: "Progresso",
- pixels: "Pixels",
- charges: "Cargas",
- estimatedTime: "Tempo estimado",
- initMessage: "Clique em 'Upload da Imagem' para começar",
- waitingInit: "Aguardando inicialização...",
- initializingToken: "🔧 Inicializando gerador de tokens Turnstile...",
- tokenReady: "✅ Gerador de tokens pronto - você pode começar a pintar!",
- tokenRetryLater: "⚠️ Gerador de tokens tentará novamente quando necessário",
- resizeSuccess: "✅ Imagem redimensionada для {width}x{height}",
- paintingPaused: "⏸️ Pintura pausada na posição X: {x}, Y: {y}",
- captchaNeeded: "❗ Falha na geração de token. Tente novamente em alguns instantes.",
- saveData: "Salvar Progresso",
- loadData: "Carregar Progresso",
- saveToFile: "Salvar em Arquivo",
- loadFromFile: "Carregar de Arquivo",
- dataManager: "Dados",
- autoSaved: "✅ Progresso salvo automaticamente",
- dataLoaded: "✅ Progresso carregado com sucesso",
- fileSaved: "✅ Salvo em arquivo com sucesso",
- fileLoaded: "✅ Carregado de arquivo com sucesso",
- noSavedData: "❌ Nenhum progresso salvo encontrado",
- savedDataFound: "✅ Progresso salvo encontrado! Carregar para continuar?",
- savedDate: "Salvo em: {date}",
- clickLoadToContinue: "Clique em 'Carregar Progresso' para continuar.",
- fileError: "❌ Erro ao processar arquivo",
- invalidFileFormat: "❌ Formato de arquivo inválido",
- paintingSpeed: "Velocidade de Pintura",
- pixelsPerSecond: "pixels/segundo",
- speedSetting: "Velocidade: {speed} pixels/seg",
- settings: "Configurações",
- botSettings: "Configurações do Bot",
- close: "Fechar",
- language: "Idioma",
- themeSettings: "Configurações de Tema",
- themeSettingsDesc: "Escolha seu tema de cores preferido para a interface.",
- languageSelectDesc: "Selecione seu idioma preferido. As alterações terão efeito imediatamente.",
- autoCaptcha: "Resolvedor de CAPTCHA Automático",
- autoCaptchaDesc: "Tenta resolver o CAPTCHA automaticamente simulando a colocação manual de um pixel quando o token expira.",
- applySettings: "Aplicar Configurações",
- settingsSaved: "✅ Configurações salvas com sucesso!",
- cooldownSettings: "Configurações de Cooldown",
- waitCharges: "Aguardar até as cargas atingirem",
- captchaSolving: "🤖 Tentando resolver o CAPTCHA...",
- captchaFailed: "❌ Falha ao resolver CAPTCHA. Pinte um pixel manualmente.",
- automation: "Automação",
- noChargesThreshold: "⌛ Aguardando cargas atingirem {threshold}. Atual: {current}. Próxima em {time}...",
- },
- vi: {
- title: "WPlace Auto-Image",
- scanColors: "Quét màu",
- uploadImage: "Tải lên hình ảnh",
- resizeImage: "Thay đổi kích thước",
- selectPosition: "Chọn vị trí",
- startPainting: "Bắt đầu vẽ",
- stopPainting: "Dừng vẽ",
- checkingColors: "🔍 Đang kiểm tra màu sắc có sẵn...",
- noColorsFound: "❌ Hãy mở bảng màu trên trang web và thử lại!",
- colorsFound: "✅ Tìm thấy {count} màu. Sẵn sàng để tải lên.",
- loadingImage: "🖼️ Đang tải hình ảnh...",
- imageLoaded: "✅ Đã tải hình ảnh với {count} pixel hợp lệ",
- imageError: "❌ Lỗi khi tải hình ảnh",
- selectPositionAlert: "Vẽ pixel đầu tiên tại vị trí bạn muốn tác phẩm nghệ thuật bắt đầu!",
- waitingPosition: "👆 Đang chờ bạn vẽ pixel tham chiếu...",
- positionSet: "✅ Đã đặt vị trí thành công!",
- positionTimeout: "❌ Hết thời gian chọn vị trí",
- startPaintingMsg: "🎨 Bắt đầu vẽ...",
- paintingProgress: "🧱 Tiến trình: {painted}/{total} pixel...",
- noCharges: "⌛ Không có điện tích. Đang chờ {time}...",
- paintingStopped: "⏹️ Người dùng đã dừng vẽ",
- paintingComplete: "✅ Hoàn thành vẽ! Đã vẽ {count} pixel.",
- paintingError: "❌ Lỗi trong quá trình vẽ",
- missingRequirements: "❌ Hãy tải lên hình ảnh và chọn vị trí trước",
- progress: "Tiến trình",
- pixels: "Pixel",
- charges: "Điện tích",
- estimatedTime: "Thời gian ước tính",
- initMessage: "Nhấp 'Tải lên hình ảnh' để bắt đầu",
- waitingInit: "Đang chờ khởi tạo...",
- initializingToken: "🔧 Đang khởi tạo bộ tạo token Turnstile...",
- tokenReady: "✅ Bộ tạo token đã sẵn sàng - bạn có thể bắt đầu vẽ!",
- tokenRetryLater: "⚠️ Bộ tạo token sẽ thử lại khi cần thiết",
- resizeSuccess: "✅ Đã thay đổi kích thước hình ảnh thành {width}x{height}",
- paintingPaused: "⏸️ Tạm dừng vẽ tại vị trí X: {x}, Y: {y}",
- captchaNeeded: "❗ Tạo token thất bại. Vui lòng thử lại sau.",
- saveData: "Lưu tiến trình",
- loadData: "Tải tiến trình",
- saveToFile: "Lưu vào tệp",
- loadFromFile: "Tải từ tệp",
- dataManager: "Dữ liệu",
- autoSaved: "✅ Đã tự động lưu tiến trình",
- dataLoaded: "✅ Đã tải tiến trình thành công",
- fileSaved: "✅ Đã lưu vào tệp thành công",
- fileLoaded: "✅ Đã tải từ tệp thành công",
- noSavedData: "❌ Không tìm thấy tiến trình đã lưu",
- savedDataFound: "✅ Tìm thấy tiến trình đã lưu! Tải để tiếp tục?",
- savedDate: "Đã lưu vào: {date}",
- clickLoadToContinue: "Nhấp 'Tải tiến trình' để tiếp tục.",
- fileError: "❌ Lỗi khi xử lý tệp",
- invalidFileFormat: "❌ Định dạng tệp không hợp lệ",
- paintingSpeed: "Tốc độ vẽ",
- pixelsPerSecond: "pixel/giây",
- speedSetting: "Tốc độ: {speed} pixel/giây",
- settings: "Cài đặt",
- botSettings: "Cài đặt Bot",
- close: "Đóng",
- language: "Ngôn ngữ",
- themeSettings: "Cài đặt Giao diện",
- themeSettingsDesc: "Chọn chủ đề màu sắc yêu thích cho giao diện.",
- languageSelectDesc: "Chọn ngôn ngữ ưa thích. Thay đổi sẽ có hiệu lực ngay lập tức.",
- autoCaptcha: "Tự động giải CAPTCHA",
- autoCaptchaDesc: "Tự động cố gắng giải CAPTCHA bằng cách mô phỏng việc đặt pixel thủ công khi token hết hạn.",
- applySettings: "Áp dụng cài đặt",
- settingsSaved: "✅ Đã lưu cài đặt thành công!",
- cooldownSettings: "Cài đặt thời gian chờ",
- waitCharges: "Chờ cho đến khi số lần sạc đạt",
- captchaSolving: "🤖 Đang cố gắng giải CAPTCHA...",
- captchaFailed: "❌ Giải CAPTCHA tự động thất bại. Vui lòng vẽ một pixel thủ công.",
- automation: "Tự động hóa",
- noChargesThreshold: "⌛ Đang chờ số lần sạc đạt {threshold}. Hiện tại {current}. Lần tiếp theo trong {time}...",
- },
- fr: {
- title: "WPlace Auto-Image",
- scanColors: "Scanner les couleurs",
- uploadImage: "Télécharger l'image",
- resizeImage: "Redimensionner l'image",
- selectPosition: "Sélectionner la position",
- startPainting: "Commencer à peindre",
- stopPainting: "Arrêter de peindre",
- checkingColors: "🔍 Vérification des couleurs disponibles...",
- noColorsFound: "❌ Ouvrez la palette de couleurs sur le site et réessayez!",
- colorsFound: "✅ {count} couleurs trouvées. Prêt à télécharger.",
- loadingImage: "🖼️ Chargement de l'image...",
- imageLoaded: "✅ Image chargée avec {count} pixels valides",
- imageError: "❌ Erreur lors du chargement de l'image",
- selectPositionAlert: "Peignez le premier pixel à l'endroit où vous voulez que l'art commence!",
- waitingPosition: "👆 En attente que vous peigniez le pixel de référence...",
- positionSet: "✅ Position définie avec succès!",
- positionTimeout: "❌ Délai d'attente pour la sélection de position",
- startPaintingMsg: "🎨 Début de la peinture...",
- paintingProgress: "🧱 Progrès: {painted}/{total} pixels...",
- noCharges: "⌛ Aucune charge. En attente {time}...",
- paintingStopped: "⏹️ Peinture arrêtée par l'utilisateur",
- paintingComplete: "✅ Peinture terminée! {count} pixels peints.",
- paintingError: "❌ Erreur pendant la peinture",
- missingRequirements: "❌ Veuillez charger une image et sélectionner une position d'abord",
- progress: "Progrès",
- pixels: "Pixels",
- charges: "Charges",
- estimatedTime: "Temps estimé",
- initMessage: "Cliquez sur 'Télécharger l'image' pour commencer",
- waitingInit: "En attente d'initialisation...",
- initializingToken: "🔧 Initialisation du générateur de tokens Turnstile...",
- tokenReady: "✅ Générateur de tokens prêt - vous pouvez commencer à peindre!",
- tokenRetryLater: "⚠️ Le générateur de tokens réessaiera si nécessaire",
- resizeSuccess: "✅ Image redimensionnée en {width}x{height}",
- paintingPaused: "⏸️ Peinture en pause à la position X: {x}, Y: {y}",
- captchaNeeded: "❗ Échec de la génération de token. Veuillez réessayer dans un moment.",
- saveData: "Sauvegarder le progrès",
- loadData: "Charger le progrès",
- saveToFile: "Sauvegarder dans un fichier",
- loadFromFile: "Charger depuis un fichier",
- dataManager: "Données",
- autoSaved: "✅ Progrès sauvegardé automatiquement",
- dataLoaded: "✅ Progrès chargé avec succès",
- fileSaved: "✅ Sauvegardé dans un fichier avec succès",
- fileLoaded: "✅ Chargé depuis un fichier avec succès",
- noSavedData: "❌ Aucun progrès sauvegardé trouvé",
- savedDataFound: "✅ Progrès sauvegardé trouvé! Charger pour continuer?",
- savedDate: "Sauvegardé le: {date}",
- clickLoadToContinue: "Cliquez sur 'Charger le progrès' pour continuer.",
- fileError: "❌ Erreur lors du traitement du fichier",
- invalidFileFormat: "❌ Format de fichier invalide",
- paintingSpeed: "Vitesse de peinture",
- pixelsPerSecond: "pixels/seconde",
- speedSetting: "Vitesse: {speed} pixels/sec",
- settings: "Paramètres",
- botSettings: "Paramètres du Bot",
- close: "Fermer",
- language: "Langue",
- themeSettings: "Paramètres de Thème",
- themeSettingsDesc: "Choisissez votre thème de couleurs préféré pour l'interface.",
- languageSelectDesc: "Sélectionnez votre langue préférée. Les changements prendront effet immédiatement.",
- autoCaptcha: "Résolveur de CAPTCHA automatique",
- autoCaptchaDesc: "Tente automatiquement de résoudre le CAPTCHA en simulant un placement manuel de pixel lorsque le jeton expire.",
- applySettings: "Appliquer les paramètres",
- settingsSaved: "✅ Paramètres enregistrés avec succès !",
- cooldownSettings: "Paramètres de recharge",
- waitCharges: "Attendre que les charges atteignent",
- captchaSolving: "🤖 Tentative de résolution du CAPTCHA...",
- captchaFailed: "❌ Échec de l'Auto-CAPTCHA. Peignez un pixel manuellement.",
- automation: "Automatisation",
- noChargesThreshold: "⌛ En attente que les charges atteignent {threshold}. Actuel: {current}. Prochaine dans {time}...",
- },
- id: {
- title: "WPlace Auto-Image",
- scanColors: "Pindai Warna",
- uploadImage: "Unggah Gambar",
- resizeImage: "Ubah Ukuran Gambar",
- selectPosition: "Pilih Posisi",
- startPainting: "Mulai Melukis",
- stopPainting: "Berhenti Melukis",
- checkingColors: "🔍 Memeriksa warna yang tersedia...",
- noColorsFound: "❌ Buka palet warna di situs dan coba lagi!",
- colorsFound: "✅ {count} warna ditemukan. Siap untuk diunggah.",
- loadingImage: "🖼️ Memuat gambar...",
- imageLoaded: "✅ Gambar dimuat dengan {count} piksel valid",
- imageError: "❌ Kesalahan saat memuat gambar",
- selectPositionAlert: "Lukis piksel pertama di lokasi tempat karya seni akan dimulai!",
- waitingPosition: "👆 Menunggu Anda melukis piksel referensi...",
- positionSet: "✅ Posisi berhasil diatur!",
- positionTimeout: "❌ Waktu habis untuk memilih posisi",
- startPaintingMsg: "🎨 Mulai melukis...",
- paintingProgress: "🧱 Progres: {painted}/{total} piksel...",
- noCharges: "⌛ Tidak ada muatan. Menunggu {time}...",
- paintingStopped: "⏹️ Melukis dihentikan oleh pengguna",
- paintingComplete: "✅ Melukis selesai! {count} piksel telah dilukis.",
- paintingError: "❌ Kesalahan selama melukis",
- missingRequirements: "❌ Unggah gambar dan pilih posisi terlebih dahulu",
- progress: "Progres",
- pixels: "Piksel",
- charges: "Muatan",
- estimatedTime: "Perkiraan waktu",
- initMessage: "Klik 'Unggah Gambar' untuk memulai",
- waitingInit: "Menunggu inisialisasi...",
- initializingToken: "🔧 Menginisialisasi generator token Turnstile...",
- tokenReady: "✅ Generator token siap - Anda bisa mulai melukis!",
- tokenRetryLater: "⚠️ Generator token akan mencoba lagi saat diperlukan",
- resizeSuccess: "✅ Gambar berhasil diubah ukurannya menjadi {width}x{height}",
- paintingPaused: "⏸️ Melukis dijeda di posisi X: {x}, Y: {y}",
- captchaNeeded: "❗ Pembuatan token gagal. Silakan coba lagi sebentar lagi.",
- saveData: "Simpan Progres",
- loadData: "Muat Progres",
- saveToFile: "Simpan ke File",
- loadFromFile: "Muat dari File",
- dataManager: "Data",
- autoSaved: "✅ Progres disimpan secara otomatis",
- dataLoaded: "✅ Progres berhasil dimuat",
- fileSaved: "✅ Berhasil disimpan ke file",
- fileLoaded: "✅ Berhasil dimuat dari file",
- noSavedData: "❌ Tidak ditemukan progres yang disimpan",
- savedDataFound: "✅ Progres yang disimpan ditemukan! Muat untuk melanjutkan?",
- savedDate: "Disimpan pada: {date}",
- clickLoadToContinue: "Klik 'Muat Progres' untuk melanjutkan.",
- fileError: "❌ Kesalahan saat memproses file",
- invalidFileFormat: "❌ Format file tidak valid",
- paintingSpeed: "Kecepatan Melukis",
- pixelsPerSecond: "piksel/detik",
- speedSetting: "Kecepatan: {speed} piksel/detik",
- settings: "Pengaturan",
- botSettings: "Pengaturan Bot",
- close: "Tutup",
- language: "Bahasa",
- themeSettings: "Pengaturan Tema",
- themeSettingsDesc: "Pilih tema warna favorit Anda untuk antarmuka.",
- languageSelectDesc: "Pilih bahasa yang Anda inginkan. Perubahan akan berlaku segera.",
- autoCaptcha: "Penyelesai CAPTCHA Otomatis",
- autoCaptchaDesc: "Mencoba menyelesaikan CAPTCHA secara otomatis dengan mensimulasikan penempatan piksel manual saat token kedaluwarsa.",
- applySettings: "Terapkan Pengaturan",
- settingsSaved: "✅ Pengaturan berhasil disimpan!",
- cooldownSettings: "Pengaturan Cooldown",
- waitCharges: "Tunggu hingga muatan mencapai",
- captchaSolving: "🤖 Mencoba menyelesaikan CAPTCHA...",
- captchaFailed: "❌ Gagal menyelesaikan CAPTCHA. Lukis satu piksel secara manual.",
- automation: "Automasi",
- noChargesThreshold: "⌛ Menunggu muatan mencapai {threshold}. Saat ini: {current}. Berikutnya dalam {time}...",
- },
- tr: {
- title: "WPlace Otomatik-Resim",
- toggleOverlay: "Katmanı Aç/Kapat",
- scanColors: "Renkleri Tara",
- uploadImage: "Resim Yükle",
- resizeImage: "Resmi Yeniden Boyutlandır",
- selectPosition: "Konum Seç",
- startPainting: "Boyamayı Başlat",
- stopPainting: "Boyamayı Durdur",
- checkingColors: "🔍 Uygun renkler kontrol ediliyor...",
- noColorsFound: "❌ Sitede renk paletini açın ve tekrar deneyin!",
- colorsFound: "✅ {count} uygun renk bulundu. Yüklemeye hazır.",
- loadingImage: "🖼️ Resim yükleniyor...",
- imageLoaded: "✅ Resim {count} geçerli piksel ile yüklendi",
- imageError: "❌ Resim yüklenirken hata oluştu",
- selectPositionAlert: "Sanatı başlatmak istediğiniz ilk pikseli boyayın!",
- waitingPosition: "👆 Referans pikseli boyamanız bekleniyor...",
- positionSet: "✅ Konum başarıyla ayarlandı!",
- positionTimeout: "❌ Konum seçme süresi doldu",
- startPaintingMsg: "🎨 Boyama başlatılıyor...",
- paintingProgress: "🧱 İlerleme: {painted}/{total} piksel...",
- noCharges: "⌛ Yeterli hak yok. Bekleniyor {time}...",
- paintingStopped: "⏹️ Boyama kullanıcı tarafından durduruldu",
- paintingComplete: "✅ Boyama tamamlandı! {count} piksel boyandı.",
- paintingError: "❌ Boyama sırasında hata oluştu",
- missingRequirements: "❌ Önce resim yükleyip konum seçmelisiniz",
- progress: "İlerleme",
- pixels: "Pikseller",
- charges: "Haklar",
- estimatedTime: "Tahmini süre",
- initMessage: "Başlamak için 'Resim Yükle'ye tıklayın",
- waitingInit: "Başlatma bekleniyor...",
- resizeSuccess: "✅ Resim {width}x{height} boyutuna yeniden boyutlandırıldı",
- paintingPaused: "⏸️ Boyama duraklatıldı, Konum X: {x}, Y: {y}",
- captchaNeeded: "❗ CAPTCHA gerekli. Devam etmek için bir pikseli manuel olarak boyayın.",
- saveData: "İlerlemeyi Kaydet",
- loadData: "İlerlemeyi Yükle",
- saveToFile: "Dosyaya Kaydet",
- loadFromFile: "Dosyadan Yükle",
- dataManager: "Veri Yöneticisi",
- autoSaved: "✅ İlerleme otomatik olarak kaydedildi",
- dataLoaded: "✅ İlerleme başarıyla yüklendi",
- fileSaved: "✅ İlerleme dosyaya başarıyla kaydedildi",
- fileLoaded: "✅ İlerleme dosyadan başarıyla yüklendi",
- noSavedData: "❌ Kayıtlı ilerleme bulunamadı",
- savedDataFound: "✅ Kayıtlı ilerleme bulundu! Devam etmek için yükleyin.",
- savedDate: "Kaydedilme tarihi: {date}",
- clickLoadToContinue: "Devam etmek için 'İlerlemeyi Yükle'ye tıklayın.",
- fileError: "❌ Dosya işlenirken hata oluştu",
- invalidFileFormat: "❌ Geçersiz dosya formatı",
- paintingSpeed: "Boyama Hızı",
- pixelsPerSecond: "piksel/saniye",
- speedSetting: "Hız: {speed} piksel/sn",
- settings: "Ayarlar",
- botSettings: "Bot Ayarları",
- close: "Kapat",
- language: "Dil",
- themeSettings: "Tema Ayarları",
- themeSettingsDesc: "Arayüz için tercih ettiğiniz renk temasını seçin.",
- languageSelectDesc: "Tercih ettiğiniz dili seçin. Değişiklikler hemen uygulanacaktır.",
- autoCaptcha: "Oto-CAPTCHA Çözücü",
- autoCaptchaDesc: "CAPTCHA süresi dolduğunda manuel piksel yerleştirmeyi taklit ederek otomatik çözmeyi dener.",
- applySettings: "Ayarları Uygula",
- settingsSaved: "✅ Ayarlar başarıyla kaydedildi!",
- cooldownSettings: "Bekleme Süresi Ayarları",
- waitCharges: "Haklar şu seviyeye ulaşana kadar bekle",
- captchaSolving: "🤖 CAPTCHA çözülmeye çalışılıyor...",
- captchaFailed: "❌ Oto-CAPTCHA başarısız oldu. Bir pikseli manuel boyayın.",
- automation: "Otomasyon",
- noChargesThreshold: "⌛ Hakların {threshold} seviyesine ulaşması bekleniyor. Şu anda {current}. Sonraki {time} içinde...",
- },
- "zh-CN": {
- title: "WPlace 自动图像",
- toggleOverlay: "切换覆盖层",
- scanColors: "扫描颜色",
- uploadImage: "上传图像",
- resizeImage: "调整大小",
- selectPosition: "选择位置",
- startPainting: "开始绘制",
- stopPainting: "停止绘制",
- checkingColors: "🔍 正在检查可用颜色...",
- noColorsFound: "❌ 请在网站上打开调色板后再试!",
- colorsFound: "✅ 找到 {count} 个可用颜色,准备上传。",
- loadingImage: "🖼️ 正在加载图像...",
- imageLoaded: "✅ 图像已加载,包含 {count} 个有效像素",
- imageError: "❌ 加载图像时出错",
- selectPositionAlert: "请在你想让作品开始的位置绘制第一个像素!",
- waitingPosition: "👆 正在等待你绘制参考像素...",
- positionSet: "✅ 位置设置成功!",
- positionTimeout: "❌ 选择位置超时",
- startPaintingMsg: "🎨 开始绘制...",
- paintingProgress: "🧱 进度: {painted}/{total} 像素...",
- noCharges: "⌛ 无可用次数,等待 {time}...",
- paintingStopped: "⏹️ 已被用户停止",
- paintingComplete: "✅ 绘制完成!共绘制 {count} 个像素。",
- paintingError: "❌ 绘制过程中出错",
- missingRequirements: "❌ 请先加载图像并选择位置",
- progress: "进度",
- pixels: "像素",
- charges: "次数",
- estimatedTime: "预计时间",
- initMessage: "点击“上传图像”开始",
- waitingInit: "正在等待初始化...",
- initializingToken: "🔧 正在初始化 Turnstile 令牌生成器...",
- tokenReady: "✅ 令牌生成器已就绪 - 可以开始绘制!",
- tokenRetryLater: "⚠️ 令牌生成器稍后将重试",
- resizeSuccess: "✅ 图像已调整为 {width}x{height}",
- paintingPaused: "⏸️ 在位置 X: {x}, Y: {y} 暂停",
- captchaNeeded: "❗ 令牌生成失败,请稍后再试。",
- saveData: "保存进度",
- loadData: "加载进度",
- saveToFile: "保存到文件",
- loadFromFile: "从文件加载",
- dataManager: "数据管理",
- autoSaved: "✅ 进度已自动保存",
- dataLoaded: "✅ 进度加载成功",
- fileSaved: "✅ 已成功保存到文件",
- fileLoaded: "✅ 已成功从文件加载",
- noSavedData: "❌ 未找到已保存进度",
- savedDataFound: "✅ 找到已保存进度!是否加载继续?",
- savedDate: "保存时间: {date}",
- clickLoadToContinue: "点击“加载进度”继续。",
- fileError: "❌ 处理文件时出错",
- invalidFileFormat: "❌ 文件格式无效",
- paintingSpeed: "绘制速度",
- pixelsPerSecond: "像素/秒",
- speedSetting: "速度: {speed} 像素/秒",
- settings: "设置",
- botSettings: "机器人设置",
- close: "关闭",
- language: "语言",
- themeSettings: "主题设置",
- themeSettingsDesc: "为界面选择你喜欢的配色主题。",
- languageSelectDesc: "选择你偏好的语言,变更立即生效。",
- autoCaptcha: "自动 CAPTCHA 解决",
- autoCaptchaDesc: "使用集成的生成器自动生成 Turnstile 令牌,必要时回退到浏览器自动化。",
- applySettings: "应用设置",
- settingsSaved: "✅ 设置保存成功!",
- speedOn: "开启",
- speedOff: "关闭",
- cooldownSettings: "冷却设置",
- waitCharges: "等待次数达到",
- captchaSolving: "🔑 正在生成 Turnstile 令牌...",
- captchaFailed: "❌ 令牌生成失败。尝试回退方法...",
- automation: "自动化",
- noChargesThreshold: "⌛ 等待次数达到 {threshold}。当前 {current}。下次在 {time}...",
- },
- "zh-TW": {
- title: "WPlace 自動圖像",
- toggleOverlay: "切換覆蓋層",
- scanColors: "掃描顏色",
- uploadImage: "上傳圖像",
- resizeImage: "調整大小",
- selectPosition: "選擇位置",
- startPainting: "開始繪製",
- stopPainting: "停止繪製",
- checkingColors: "🔍 正在檢查可用顏色...",
- noColorsFound: "❌ 請在網站上打開調色板後再試!",
- colorsFound: "✅ 找到 {count} 個可用顏色,準備上傳。",
- loadingImage: "🖼️ 正在載入圖像...",
- imageLoaded: "✅ 圖像已載入,包含 {count} 個有效像素",
- imageError: "❌ 載入圖像時出錯",
- selectPositionAlert: "請在你想讓作品開始的位置繪製第一個像素!",
- waitingPosition: "👆 正在等待你繪製參考像素...",
- positionSet: "✅ 位置設定成功!",
- positionTimeout: "❌ 選擇位置逾時",
- startPaintingMsg: "🎨 開始繪製...",
- paintingProgress: "🧱 進度: {painted}/{total} 像素...",
- noCharges: "⌛ 無可用次數,等待 {time}...",
- paintingStopped: "⏹️ 已被使用者停止",
- paintingComplete: "✅ 繪製完成!共繪製 {count} 個像素。",
- paintingError: "❌ 繪製過程中出錯",
- missingRequirements: "❌ 請先載入圖像並選擇位置",
- progress: "進度",
- pixels: "像素",
- charges: "次數",
- estimatedTime: "預計時間",
- initMessage: "點擊「上傳圖像」開始",
- waitingInit: "正在等待初始化...",
- initializingToken: "🔧 正在初始化 Turnstile 令牌產生器...",
- tokenReady: "✅ 令牌產生器已就緒 - 可以開始繪製!",
- tokenRetryLater: "⚠️ 令牌產生器稍後將重試",
- resizeSuccess: "✅ 圖像已調整為 {width}x{height}",
- paintingPaused: "⏸️ 在位置 X: {x}, Y: {y} 暫停",
- captchaNeeded: "❗ 令牌產生失敗,請稍後再試。",
- saveData: "儲存進度",
- loadData: "載入進度",
- saveToFile: "儲存至檔案",
- loadFromFile: "從檔案載入",
- dataManager: "資料管理",
- autoSaved: "✅ 進度已自動儲存",
- dataLoaded: "✅ 進度載入成功",
- fileSaved: "✅ 已成功儲存至檔案",
- fileLoaded: "✅ 已成功從檔案載入",
- noSavedData: "❌ 未找到已儲存進度",
- savedDataFound: "✅ 找到已儲存進度!是否載入以繼續?",
- savedDate: "儲存時間: {date}",
- clickLoadToContinue: "點擊「載入進度」繼續。",
- fileError: "❌ 處理檔案時出錯",
- invalidFileFormat: "❌ 檔案格式無效",
- paintingSpeed: "繪製速度",
- pixelsPerSecond: "像素/秒",
- speedSetting: "速度: {speed} 像素/秒",
- settings: "設定",
- botSettings: "機器人設定",
- close: "關閉",
- language: "語言",
- themeSettings: "主題設定",
- themeSettingsDesc: "為介面選擇你喜歡的配色主題。",
- languageSelectDesc: "選擇你偏好的語言,變更立即生效。",
- autoCaptcha: "自動 CAPTCHA 解決",
- autoCaptchaDesc: "使用整合的產生器自動產生 Turnstile 令牌,必要時回退到瀏覽器自動化。",
- applySettings: "套用設定",
- settingsSaved: "✅ 設定儲存成功!",
- speedOn: "開啟",
- speedOff: "關閉",
- cooldownSettings: "冷卻設定",
- waitCharges: "等待次數達到",
- captchaSolving: "🔑 正在產生 Turnstile 令牌...",
- captchaFailed: "❌ 令牌產生失敗。嘗試回退方法...",
- automation: "自動化",
- noChargesThreshold: "⌛ 等待次數達到 {threshold}。目前 {current}。下次在 {time}...",
- },
- ja: {
- title: "WPlace 自動画像",
- toggleOverlay: "オーバーレイ切替",
- scanColors: "色をスキャン",
- uploadImage: "画像をアップロード",
- resizeImage: "画像サイズ変更",
- selectPosition: "位置を選択",
- startPainting: "描画開始",
- stopPainting: "描画停止",
- checkingColors: "🔍 利用可能な色を確認中...",
- noColorsFound: "❌ サイトでカラーパレットを開いて再試行してください!",
- colorsFound: "✅ 利用可能な色 {count} 件を検出。アップロード可能。",
- loadingImage: "🖼️ 画像を読み込み中...",
- imageLoaded: "✅ 画像を読み込みました。有効なピクセル {count}",
- imageError: "❌ 画像の読み込みエラー",
- selectPositionAlert: "作品を開始したい位置に最初のピクセルを置いてください!",
- waitingPosition: "👆 参照ピクセルの描画を待っています...",
- positionSet: "✅ 位置を設定しました!",
- positionTimeout: "❌ 位置選択のタイムアウト",
- startPaintingMsg: "🎨 描画を開始...",
- paintingProgress: "🧱 進捗: {painted}/{total} ピクセル...",
- noCharges: "⌛ チャージなし。{time} 待機...",
- paintingStopped: "⏹️ ユーザーにより停止されました",
- paintingComplete: "✅ 描画完了! {count} ピクセル描画。",
- paintingError: "❌ 描画中にエラー",
- missingRequirements: "❌ 先に画像を読み込み位置を選択してください",
- progress: "進捗",
- pixels: "ピクセル",
- charges: "チャージ",
- estimatedTime: "推定時間",
- initMessage: "「画像をアップロード」をクリックして開始",
- waitingInit: "初期化待機中...",
- initializingToken: "🔧 Turnstile トークン生成器を初期化中...",
- tokenReady: "✅ トークン生成器準備完了 - 描画できます!",
- tokenRetryLater: "⚠️ 必要に応じて再試行します",
- resizeSuccess: "✅ 画像を {width}x{height} にリサイズ",
- paintingPaused: "⏸️ X: {x}, Y: {y} で一時停止",
- captchaNeeded: "❗ トークン生成に失敗。少ししてから再試行してください。",
- saveData: "進捗を保存",
- loadData: "進捗を読み込み",
- saveToFile: "ファイルへ保存",
- loadFromFile: "ファイルから読み込み",
- dataManager: "データ管理",
- autoSaved: "✅ 自動保存しました",
- dataLoaded: "✅ 進捗を読み込みました",
- fileSaved: "✅ ファイルに保存しました",
- fileLoaded: "✅ ファイルから読み込みました",
- noSavedData: "❌ 保存された進捗がありません",
- savedDataFound: "✅ 保存された進捗が見つかりました。続行しますか?",
- savedDate: "保存日時: {date}",
- clickLoadToContinue: "「進捗を読み込み」をクリックして続行。",
- fileError: "❌ ファイル処理エラー",
- invalidFileFormat: "❌ 無効なファイル形式",
- paintingSpeed: "描画速度",
- pixelsPerSecond: "ピクセル/秒",
- speedSetting: "速度: {speed} ピクセル/秒",
- settings: "設定",
- botSettings: "ボット設定",
- close: "閉じる",
- language: "言語",
- themeSettings: "テーマ設定",
- themeSettingsDesc: "インターフェースの好きなカラーテーマを選択。",
- languageSelectDesc: "希望言語を選択。変更は即時反映されます。",
- autoCaptcha: "自動 CAPTCHA ソルバー",
- autoCaptchaDesc: "統合ジェネレーターで Turnstile トークンを自動生成し必要に応じてブラウザ自動化にフォールバック。",
- applySettings: "設定を適用",
- settingsSaved: "✅ 設定を保存しました!",
- speedOn: "オン",
- speedOff: "オフ",
- cooldownSettings: "クールダウン設定",
- waitCharges: "チャージ数が次に達するまで待機",
- captchaSolving: "🔑 Turnstile トークン生成中...",
- captchaFailed: "❌ トークン生成失敗。フォールバックを試行...",
- automation: "自動化",
- noChargesThreshold: "⌛ チャージ {threshold} を待機中。現在 {current}。次は {time} 後...",
- },
- ko: {
- title: "WPlace 자동 이미지",
- toggleOverlay: "오버레이 전환",
- scanColors: "색상 스캔",
- uploadImage: "이미지 업로드",
- resizeImage: "크기 조정",
- selectPosition: "위치 선택",
- startPainting: "그리기 시작",
- stopPainting: "그리기 중지",
- checkingColors: "🔍 사용 가능한 색상 확인 중...",
- noColorsFound: "❌ 사이트에서 색상 팔레트를 연 후 다시 시도하세요!",
- colorsFound: "✅ 사용 가능한 색상 {count}개 발견. 업로드 준비 완료.",
- loadingImage: "🖼️ 이미지 불러오는 중...",
- imageLoaded: "✅ 이미지 로드 완료. 유효 픽셀 {count}개",
- imageError: "❌ 이미지 로드 오류",
- selectPositionAlert: "작품을 시작할 위치에 첫 픽셀을 칠하세요!",
- waitingPosition: "👆 기준 픽셀을 칠할 때까지 대기 중...",
- positionSet: "✅ 위치 설정 완료!",
- positionTimeout: "❌ 위치 선택 시간 초과",
- startPaintingMsg: "🎨 그리기 시작...",
- paintingProgress: "🧱 진행: {painted}/{total} 픽셀...",
- noCharges: "⌛ 사용 가능 횟수 없음. {time} 대기...",
- paintingStopped: "⏹️ 사용자에 의해 중지됨",
- paintingComplete: "✅ 그리기 완료! {count} 픽셀 그렸습니다.",
- paintingError: "❌ 그리는 중 오류",
- missingRequirements: "❌ 먼저 이미지를 불러오고 위치를 선택하세요",
- progress: "진행",
- pixels: "픽셀",
- charges: "횟수",
- estimatedTime: "예상 시간",
- initMessage: "'이미지 업로드'를 클릭하여 시작",
- waitingInit: "초기화 대기 중...",
- initializingToken: "🔧 Turnstile 토큰 생성기 초기화 중...",
- tokenReady: "✅ 토큰 생성 준비 완료 - 그리기를 시작할 수 있습니다!",
- tokenRetryLater: "⚠️ 필요 시 다시 시도합니다",
- resizeSuccess: "✅ 이미지가 {width}x{height} 크기로 조정됨",
- paintingPaused: "⏸️ 위치 X: {x}, Y: {y} 에서 일시 중지",
- captchaNeeded: "❗ 토큰 생성 실패. 잠시 후 다시 시도하세요.",
- saveData: "진행 저장",
- loadData: "진행 불러오기",
- saveToFile: "파일로 저장",
- loadFromFile: "파일에서 불러오기",
- dataManager: "데이터",
- autoSaved: "✅ 진행 자동 저장됨",
- dataLoaded: "✅ 진행 불러오기 성공",
- fileSaved: "✅ 파일 저장 성공",
- fileLoaded: "✅ 파일 불러오기 성공",
- noSavedData: "❌ 저장된 진행 없음",
- savedDataFound: "✅ 저장된 진행 발견! 계속하려면 불러오시겠습니까?",
- savedDate: "저장 시각: {date}",
- clickLoadToContinue: "'진행 불러오기'를 클릭하여 계속.",
- fileError: "❌ 파일 처리 오류",
- invalidFileFormat: "❌ 잘못된 파일 형식",
- paintingSpeed: "그리기 속도",
- pixelsPerSecond: "픽셀/초",
- speedSetting: "속도: {speed} 픽셀/초",
- settings: "설정",
- botSettings: "봇 설정",
- close: "닫기",
- language: "언어",
- themeSettings: "테마 설정",
- themeSettingsDesc: "인터페이스용 선호 색상 테마를 선택하세요.",
- languageSelectDesc: "선호 언어를 선택하세요. 변경 사항은 즉시 적용됩니다.",
- autoCaptcha: "자동 CAPTCHA 해결",
- autoCaptchaDesc: "통합 생성기를 사용해 Turnstile 토큰을 자동 생성하고 필요 시 브라우저 자동화로 폴백.",
- applySettings: "설정 적용",
- settingsSaved: "✅ 설정 저장 완료!",
- speedOn: "켜짐",
- speedOff: "꺼짐",
- cooldownSettings: "쿨다운 설정",
- waitCharges: "횟수가 다음 값에 도달할 때까지 대기",
- captchaSolving: "🔑 Turnstile 토큰 생성 중...",
- captchaFailed: "❌ 토큰 생성 실패. 폴백 시도...",
- automation: "자동화",
- noChargesThreshold: "⌛ 횟수가 {threshold} 에 도달할 때까지 대기 중. 현재 {current}. 다음 {time} 후...",
- },
- uk: {
- title: "WPlace Авто-Зображення",
- toggleOverlay: "Перемкнути оверлей",
- scanColors: "Сканувати кольори",
- uploadImage: "Завантажити зображення",
- resizeImage: "Змінити розмір зображення",
- selectPosition: "Вибрати позицію",
- startPainting: "Почати малювання",
- stopPainting: "Зупинити малювання",
- checkingColors: "🔍 Перевірка доступних кольорів...",
- noColorsFound: "❌ Відкрий палітру кольорів на сайті та спробуй ще раз!",
- colorsFound: "✅ Знайдено {count} доступних кольорів. Готово до завантаження.",
- loadingImage: "🖼️ Завантаження зображення...",
- imageLoaded: "✅ Зображення завантажено. Валідних пікселів: {count}",
- imageError: "❌ Помилка завантаження зображення",
- selectPositionAlert: "Намалюй перший піксель у місці, де має починатися арт!",
- waitingPosition: "👆 Очікування на малювання референсного пікселя...",
- positionSet: "✅ Позицію успішно встановлено!",
- positionTimeout: "❌ Час вибору позиції вичерпано",
- startPaintingMsg: "🎨 Початок малювання...",
- paintingProgress: "🧱 Прогрес: {painted}/{total} пікселів...",
- noCharges: "⌛ Немає зарядів. Очікування {time}...",
- paintingStopped: "⏹️ Малювання зупинено користувачем",
- paintingComplete: "✅ Малювання завершено! Намальовано {count} пікселів.",
- paintingError: "❌ Помилка під час малювання",
- missingRequirements: "❌ Спершу завантаж зображення та вибери позицію",
- progress: "Прогрес",
- pixels: "Пікселі",
- charges: "Заряди",
- estimatedTime: "Орієнтовний час",
- initMessage: "Натисни 'Завантажити зображення', щоб почати",
- waitingInit: "Очікування ініціалізації...",
- initializingToken: "🔧 Ініціалізація генератора токенів Turnstile...",
- tokenReady: "✅ Генератор токенів готовий – можна починати малювання!",
- tokenRetryLater: "⚠️ Генератор токенів повторить спробу за потреби",
- resizeSuccess: "✅ Зображення змінено до {width}x{height}",
- paintingPaused: "⏸️ Малювання призупинено на позиції X: {x}, Y: {y}",
- captchaNeeded: "❗ Не вдалося згенерувати токен. Спробуй трохи пізніше.",
- saveData: "Зберегти прогрес",
- loadData: "Завантажити прогрес",
- saveToFile: "Зберегти у файл",
- loadFromFile: "Завантажити з файлу",
- dataManager: "Менеджер даних",
- autoSaved: "✅ Прогрес збережено автоматично",
- dataLoaded: "✅ Прогрес успішно завантажено",
- fileSaved: "✅ Прогрес успішно збережено у файл",
- fileLoaded: "✅ Прогрес успішно завантажено з файлу",
- noSavedData: "❌ Не знайдено збереженого прогресу",
- savedDataFound: "✅ Знайдено збережений прогрес! Завантажити, щоб продовжити?",
- savedDate: "Збережено: {date}",
- clickLoadToContinue: "Натисни 'Завантажити прогрес', щоб продовжити.",
- fileError: "❌ Помилка обробки файлу",
- invalidFileFormat: "❌ Невірний формат файлу",
- paintingSpeed: "Швидкість малювання",
- pixelsPerSecond: "пікселів/секунда",
- speedSetting: "Швидкість: {speed} пікселів/сек",
- settings: "Налаштування",
- botSettings: "Налаштування бота",
- close: "Закрити",
- language: "Мова",
- themeSettings: "Налаштування теми",
- themeSettingsDesc: "Вибери бажану колірну тему для інтерфейсу.",
- languageSelectDesc: "Вибери бажану мову. Зміни набудуть чинності одразу.",
- autoCaptcha: "Авто-CAPTCHA (Turnstile)",
- autoCaptchaDesc: "Автоматично генерує токени Turnstile за допомогою вбудованого генератора. Використовує автоматизацію браузера у разі потреби.",
- applySettings: "Застосувати налаштування",
- settingsSaved: "✅ Налаштування успішно збережено!",
- cooldownSettings: "Налаштування відновлення",
- waitCharges: "Очікувати, доки кількість зарядів досягне",
- captchaSolving: "🔑 Генерація токена Turnstile...",
- captchaFailed: "❌ Не вдалося згенерувати токен Turnstile. Використовую запасний метод...",
- automation: "Автоматизація",
- noChargesThreshold: "⌛ Очікування, доки заряди досягнуть {threshold}. Зараз {current}. Наступне через {time}...",
- },
- }
+ loadingError: "Loading translations failed, using fallback"
+ }
+ };
// GLOBAL STATE
const state = {
@@ -2146,7 +1315,7 @@
},
t: async (key, params = {}) => {
- // Try to get from ngrok first, with caching
+ // Try to get from cache first
const cacheKey = `${state.language}_${key}`;
if (translationCache.has(cacheKey)) {
let text = translationCache.get(cacheKey);
@@ -2156,32 +1325,57 @@
return text;
}
- // Try fetching from ngrok
- try {
- const response = await fetch(`TODO: /translations/${state.language}.json`, {
- headers: {
- "ngrok-skip-browser-warning": "69420"
- }
+ // Try dynamically loaded translations
+ if (loadedTranslations[state.language]?.[key]) {
+ let text = loadedTranslations[state.language][key];
+ // Cache for future use
+ translationCache.set(cacheKey, text);
+ Object.keys(params).forEach((param) => {
+ text = text.replace(`{${param}}`, params[param]);
});
-
- if (response.ok) {
- const translations = await response.json();
- if (translations[key]) {
- // Cache the successful translation
- translationCache.set(cacheKey, translations[key]);
+ return text;
+ }
+
+ // Try to load translations if not loaded yet
+ if (!loadedTranslations[state.language]) {
+ try {
+ const translations = await loadTranslations(state.language);
+ if (translations?.[key]) {
let text = translations[key];
+ translationCache.set(cacheKey, text);
Object.keys(params).forEach((param) => {
text = text.replace(`{${param}}`, params[param]);
});
return text;
}
+ } catch (error) {
+ console.warn(`Translation loading failed for ${state.language}:`, error);
}
- } catch (error) {
- // Silently fail and use fallback
}
- // Fallback to local TEXT
- let text = TEXT[state.language]?.[key] || TEXT.en[key] || key;
+ // Fallback to English if current language failed
+ if (state.language !== 'en') {
+ if (loadedTranslations['en']?.[key]) {
+ let text = loadedTranslations['en'][key];
+ Object.keys(params).forEach((param) => {
+ text = text.replace(`{${param}}`, params[param]);
+ });
+ return text;
+ }
+
+ // Try to load English translations
+ const englishTranslations = await loadTranslations('en');
+ if (englishTranslations?.[key]) {
+ let text = englishTranslations[key];
+ Object.keys(params).forEach((param) => {
+ text = text.replace(`{${param}}`, params[param]);
+ });
+ return text;
+ }
+ }
+
+ // Final fallback to emergency fallback or key
+ let text = FALLBACK_TEXT[state.language]?.[key] || FALLBACK_TEXT.en?.[key] || key;
Object.keys(params).forEach((param) => {
text = text.replace(`{${param}}`, params[param]);
});
@@ -3380,7 +2574,7 @@
if (existingResizeOverlay) existingResizeOverlay.remove()
loadThemePreference()
- loadLanguagePreference()
+ await loadLanguagePreference()
const theme = getCurrentTheme()
@@ -5698,11 +4892,14 @@
const languageSelect = settingsContainer.querySelector("#languageSelect")
if (languageSelect) {
- languageSelect.addEventListener("change", (e) => {
+ languageSelect.addEventListener("change", async (e) => {
const newLanguage = e.target.value
state.language = newLanguage
localStorage.setItem('wplace_language', newLanguage)
+ // Load the new language translations
+ await loadTranslations(newLanguage)
+
setTimeout(() => {
settingsContainer.style.display = "none"
createUI()
From 8313fed149a9c2c629dcd090387a9555941c27ba Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Wed, 27 Aug 2025 23:54:20 +0200
Subject: [PATCH 08/14] no more `[object Promise]`???
---
Auto-Image.js | 51 ++++++++++++++-------------------------------------
1 file changed, 14 insertions(+), 37 deletions(-)
diff --git a/Auto-Image.js b/Auto-Image.js
index 3d633c7..bf340ad 100644
--- a/Auto-Image.js
+++ b/Auto-Image.js
@@ -244,6 +244,11 @@
state.language = "en"
await loadTranslations("en")
}
+
+ // Always ensure English is loaded as fallback
+ if (!loadedTranslations["en"]) {
+ await loadTranslations("en")
+ }
// Simple translation cache
const translationCache = new Map();
@@ -1314,7 +1319,8 @@
return button
},
- t: async (key, params = {}) => {
+ // Synchronous translation function for UI rendering
+ t: (key, params = {}) => {
// Try to get from cache first
const cacheKey = `${state.language}_${key}`;
if (translationCache.has(cacheKey)) {
@@ -1325,7 +1331,7 @@
return text;
}
- // Try dynamically loaded translations
+ // Try dynamically loaded translations (already loaded)
if (loadedTranslations[state.language]?.[key]) {
let text = loadedTranslations[state.language][key];
// Cache for future use
@@ -1336,42 +1342,13 @@
return text;
}
- // Try to load translations if not loaded yet
- if (!loadedTranslations[state.language]) {
- try {
- const translations = await loadTranslations(state.language);
- if (translations?.[key]) {
- let text = translations[key];
- translationCache.set(cacheKey, text);
- Object.keys(params).forEach((param) => {
- text = text.replace(`{${param}}`, params[param]);
- });
- return text;
- }
- } catch (error) {
- console.warn(`Translation loading failed for ${state.language}:`, error);
- }
- }
-
// Fallback to English if current language failed
- if (state.language !== 'en') {
- if (loadedTranslations['en']?.[key]) {
- let text = loadedTranslations['en'][key];
- Object.keys(params).forEach((param) => {
- text = text.replace(`{${param}}`, params[param]);
- });
- return text;
- }
-
- // Try to load English translations
- const englishTranslations = await loadTranslations('en');
- if (englishTranslations?.[key]) {
- let text = englishTranslations[key];
- Object.keys(params).forEach((param) => {
- text = text.replace(`{${param}}`, params[param]);
- });
- return text;
- }
+ if (state.language !== 'en' && loadedTranslations['en']?.[key]) {
+ let text = loadedTranslations['en'][key];
+ Object.keys(params).forEach((param) => {
+ text = text.replace(`{${param}}`, params[param]);
+ });
+ return text;
}
// Final fallback to emergency fallback or key
From 7940410f8f6fdb2978493de3640a6440978ff1e0 Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Wed, 27 Aug 2025 23:56:55 +0200
Subject: [PATCH 09/14] ReferenceError: Cannot access 'loadedTranslations'
before initialization should now be fixed
---
Auto-Image.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/Auto-Image.js b/Auto-Image.js
index bf340ad..8660eb6 100644
--- a/Auto-Image.js
+++ b/Auto-Image.js
@@ -211,6 +211,12 @@
}
}
+ // Simple translation cache
+ const translationCache = new Map();
+
+ // Dynamically loaded translations
+ let loadedTranslations = {};
+
const loadLanguagePreference = async () => {
const savedLanguage = localStorage.getItem("wplace_language")
@@ -250,12 +256,6 @@
await loadTranslations("en")
}
- // Simple translation cache
- const translationCache = new Map();
-
- // Dynamically loaded translations
- let loadedTranslations = {};
-
// Available languages
const AVAILABLE_LANGUAGES = ['en', 'ru', 'pt', 'vi', 'fr', 'id', 'tr', 'zh-CN', 'zh-TW', 'ja', 'ko', 'uk'];
From d2dab0538999be886b6994f9f4e04de96c0f1dd3 Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Wed, 27 Aug 2025 23:59:35 +0200
Subject: [PATCH 10/14] Uncaught (in promise) ReferenceError: Cannot access
'loadTranslations' before initialization should be fixed
---
Auto-Image.js | 60 +++++++++++++++++++++++++--------------------------
1 file changed, 30 insertions(+), 30 deletions(-)
diff --git a/Auto-Image.js b/Auto-Image.js
index 8660eb6..e795118 100644
--- a/Auto-Image.js
+++ b/Auto-Image.js
@@ -217,6 +217,36 @@
// Dynamically loaded translations
let loadedTranslations = {};
+ // Available languages
+ const AVAILABLE_LANGUAGES = ['en', 'ru', 'pt', 'vi', 'fr', 'id', 'tr', 'zh-CN', 'zh-TW', 'ja', 'ko', 'uk'];
+
+ // Function to load translations from JSON file
+ const loadTranslations = async (language) => {
+ if (loadedTranslations[language]) {
+ return loadedTranslations[language];
+ }
+
+ // Load translations from CDN
+ const url = `https://staninna.github.io/WPlace-AutoBOT/decoupled-translations/lang/${language}.json`;
+
+ try {
+ console.log(`🔄 Loading ${language} translations from CDN...`);
+ const response = await fetch(url);
+ if (response.ok) {
+ const translations = await response.json();
+ loadedTranslations[language] = translations;
+ console.log(`📚 Loaded ${language} translations successfully from CDN`);
+ return translations;
+ } else {
+ console.warn(`❌ CDN returned HTTP ${response.status}: ${response.statusText} for ${language} translations`);
+ }
+ } catch (error) {
+ console.error(`❌ Failed to load ${language} translations from CDN:`, error);
+ }
+
+ return null;
+ };
+
const loadLanguagePreference = async () => {
const savedLanguage = localStorage.getItem("wplace_language")
@@ -256,36 +286,6 @@
await loadTranslations("en")
}
- // Available languages
- const AVAILABLE_LANGUAGES = ['en', 'ru', 'pt', 'vi', 'fr', 'id', 'tr', 'zh-CN', 'zh-TW', 'ja', 'ko', 'uk'];
-
- // Function to load translations from JSON file
- const loadTranslations = async (language) => {
- if (loadedTranslations[language]) {
- return loadedTranslations[language];
- }
-
- // Load translations from CDN
- const url = `https://staninna.github.io/WPlace-AutoBOT/decoupled-translations/lang/${language}.json`;
-
- try {
- console.log(`🔄 Loading ${language} translations from CDN...`);
- const response = await fetch(url);
- if (response.ok) {
- const translations = await response.json();
- loadedTranslations[language] = translations;
- console.log(`📚 Loaded ${language} translations successfully from CDN`);
- return translations;
- } else {
- console.warn(`❌ CDN returned HTTP ${response.status}: ${response.statusText} for ${language} translations`);
- }
- } catch (error) {
- console.error(`❌ Failed to load ${language} translations from CDN:`, error);
- }
-
- return null;
- };
-
// Emergency fallback TEXT (minimal)
const FALLBACK_TEXT = {
en: {
From c10a87dc74bc668fa20ee1e46e59aace679c10e9 Mon Sep 17 00:00:00 2001
From: Staninna <26458805+Staninna@users.noreply.github.com>
Date: Thu, 28 Aug 2025 00:25:51 +0200
Subject: [PATCH 11/14] Claude limit reached. WIP English copied text from
JSON; translation to native language in progress
---
Auto-Image.js | 108 ++++++++++++++++++++++++------------------------
lang/en.json | 64 +++++++++++++++++++++++++++-
lang/fr.json | 75 +++++++++++++++++++++++++++++----
lang/id.json | 64 +++++++++++++++++++++++++++-
lang/ja.json | 65 ++++++++++++++++++++++++++++-
lang/ko.json | 65 ++++++++++++++++++++++++++++-
lang/pt.json | 64 +++++++++++++++++++++++++++-
lang/ru.json | 64 +++++++++++++++++++++++++++-
lang/tr.json | 65 ++++++++++++++++++++++++++++-
lang/uk.json | 65 ++++++++++++++++++++++++++++-
lang/vi.json | 67 ++++++++++++++++++++++++++++--
lang/zh-CN.json | 67 ++++++++++++++++++++++++++++--
lang/zh-TW.json | 65 ++++++++++++++++++++++++++++-
13 files changed, 814 insertions(+), 84 deletions(-)
diff --git a/Auto-Image.js b/Auto-Image.js
index e795118..d316d69 100644
--- a/Auto-Image.js
+++ b/Auto-Image.js
@@ -871,7 +871,7 @@
if (source === 'turnstile-capture' && token) {
setTurnstileToken(token);
if (document.querySelector("#statusText")?.textContent.includes("CAPTCHA")) {
- Utils.showAlert("Token captured successfully! You can start the bot now.", "success");
+ Utils.showAlert(Utils.t("tokenCapturedSuccess"), "success");
updateUI("colorsFound", "success", { count: state.availableColors.length });
}
}
@@ -991,7 +991,7 @@
`;
const title = document.createElement('div');
- title.textContent = 'Cloudflare Turnstile — please complete the check if shown';
+ title.textContent = Utils.t('turnstileInstructions');
title.style.cssText = 'font: 600 12px/1.3 "Segoe UI",sans-serif; margin-bottom: 8px; opacity: 0.9;';
const host = document.createElement('div');
@@ -999,7 +999,7 @@
host.style.cssText = 'width: 100%; min-height: 70px;';
const hideBtn = document.createElement('button');
- hideBtn.textContent = 'Hide';
+ hideBtn.textContent = Utils.t('hideTurnstileBtn');
hideBtn.style.cssText = 'position:absolute; top:6px; right:6px; font-size:11px; background:transparent; color:#fff; border:1px solid rgba(255,255,255,0.2); border-radius:6px; padding:2px 6px; cursor:pointer;';
hideBtn.addEventListener('click', () => overlay.remove());
@@ -2150,7 +2150,7 @@
},
async requestPermission() {
if (!("Notification" in window)) {
- Utils.showAlert("Notifications are not supported in this browser.", "warning");
+ Utils.showAlert(Utils.t("notificationsNotSupported"), "warning");
return "denied";
}
if (Notification.permission === "granted") return "granted";
@@ -2198,8 +2198,8 @@
const shouldEdge = state._lastChargesBelow || force;
const shouldRepeat = now - (state._lastChargesNotifyAt || 0) >= repeatMs;
if (shouldEdge || shouldRepeat) {
- const msg = `Charges ready: ${Math.floor(state.currentCharges)} / ${state.maxCharges}. Threshold: ${state.cooldownChargeThreshold}.`;
- this.notify("WPlace — Charges Ready", msg, "wplace-notify-charges");
+ const msg = Utils.t("chargesReadyMessage", { current: Math.floor(state.currentCharges), max: state.maxCharges, threshold: state.cooldownChargeThreshold });
+ this.notify(Utils.t("chargesReadyNotification"), msg, "wplace-notify-charges");
state._lastChargesNotifyAt = now;
}
state._lastChargesBelow = false;
@@ -2336,7 +2336,7 @@
// Don't re-fetch colors here, use what was captured when user clicked upload
if (!state.availableColors || state.availableColors.length === 0) {
// If no colors have been captured yet, show message
- colorsContainer.innerHTML = 'Upload an image first to capture available colors
';
+ colorsContainer.innerHTML = `${Utils.t('uploadImageFirst')}
`;
return;
}
@@ -3729,10 +3729,10 @@
-