14 Commits

Author SHA1 Message Date
c22c2fb254 Feature multi-attack in same second
All checks were successful
Continuous Deployment / lint (push) Successful in 26s
Continuous Deployment / deploy-chrome (push) Successful in 32s
Continuous Deployment / deploy-firefox (push) Successful in 5m36s
2025-11-13 20:13:50 +01:00
4fe2922e5a Fix display navbar with reports
All checks were successful
Continuous Deployment / lint (push) Successful in 26s
Continuous Deployment / deploy-chrome (push) Successful in 31s
Continuous Deployment / deploy-firefox (push) Successful in 2m43s
2025-11-13 10:31:12 +01:00
4f1d5442be Continuous deployment on Chrome
Some checks failed
Continuous Deployment / lint (push) Successful in 28s
Continuous Deployment / deploy-chrome (push) Successful in 31s
Continuous Deployment / deploy-firefox (push) Failing after 26s
2025-11-13 01:17:56 +01:00
45d5200e61 Fix bug menu
All checks were successful
Continuous Deployment / lint (push) Successful in 29s
Continuous Deployment / deploy (push) Successful in 5m8s
2025-11-11 23:39:57 +01:00
10de4507af Add data collection permissions
All checks were successful
Continuous Deployment / lint (push) Successful in 30s
Continuous Deployment / deploy (push) Successful in 56s
2025-11-11 17:34:00 +01:00
a37d54cd2e Fix metadata.json format
All checks were successful
Continuous Deployment / lint (push) Successful in 30s
Continuous Deployment / deploy (push) Successful in 3m20s
2025-11-11 16:36:50 +01:00
abc7742b75 Remove data_collection_permissions because not supported for android
All checks were successful
Continuous Deployment / lint (push) Successful in 30s
Continuous Deployment / deploy (push) Successful in 5m20s
2025-11-11 14:58:51 +01:00
05369a6661 Update version before tagging
All checks were successful
Continuous Deployment / lint (push) Successful in 1m27s
Continuous Deployment / deploy (push) Successful in 4m33s
2025-11-11 14:29:00 +01:00
948de12bc5 Add web ext key and secret in workflow 2025-11-11 14:26:41 +01:00
f7cb4da37c Setup continuous deployment
Some checks failed
Continuous Deployment / lint (push) Successful in 1m26s
Continuous Deployment / deploy (push) Failing after 15s
2025-11-11 13:48:48 +01:00
89c5c127c5 create makefile 2025-10-22 11:29:03 +02:00
2b1eb25a28 Add Makefile 2025-09-15 11:00:47 +02:00
2ca48bda23 Change notif point from image to css background 2025-09-15 10:57:03 +02:00
57d83653d5 Fix messages with notifs in menu 2025-09-15 10:56:29 +02:00
9 changed files with 265 additions and 88 deletions

41
.gitea/workflows/cd.yaml Normal file
View File

@@ -0,0 +1,41 @@
name: Continuous Deployment
on:
push:
tags:
- v*
jobs:
lint:
runs-on: linux
steps:
- name: Checkout repo
uses: actions/checkout@v5
- name: Run linter
run: make lint
deploy-chrome:
needs: lint
runs-on: linux
steps:
- name: Checkout repo
uses: actions/checkout@v5
- name: Deploy project to Chrome Webstore
env:
CLIENT_ID: ${{ vars.CHROME_CLIENT_ID }}
CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }}
EXTENSION_ID: ${{ vars.CHROME_EXTENSION_ID }}
REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }}
run: make deploy_chrome
deploy-firefox:
needs: lint
runs-on: linux
steps:
- name: Checkout repo
uses: actions/checkout@v5
- name: Deploy project to Firefox Addons
env:
WEB_EXT_API_KEY: ${{ vars.FIREFOX_API_KEY }}
WEB_EXT_API_SECRET: ${{ secrets.FIREFOX_API_SECRET }}
run: make deploy_firefox

1
.gitignore vendored
View File

@@ -1 +1,2 @@
web-ext-artifacts/ web-ext-artifacts/
.idea/

View File

@@ -1,5 +1,60 @@
# Changelog # Changelog
## 1.5.1 (2025-11-13)
- fonctionnalité de multi-attaques dans la même seconde
## 1.4.14 (2025-11-13)
- correction affichage menu avec rapports
## 1.4.13 (2025-11-13)
- déploiement automatique sur chrome
## 1.4.12 (2025-11-11)
- correction bug menu
## 1.4.11 (2025-11-11)
- ajout des data collection permissions
## 1.4.10 (2025-11-11)
- correction du fichier metadata.json
## 1.4.9 (2025-11-11)
- test déploiement manuel
## 1.4.8 (2025-11-11)
- suppression de data_collection_permissions car non supporté pour Android
## 1.4.7 (2025-11-11)
- correction du déploiement automatisé
- ajout de data_collection_permissions dans manifest.json
## 1.4.6 (2025-11-11)
- déploiement automatisé sur firefox
- correction du bug d'affichage du menu Messages et Rapports
## 1.4.5 (2025-10-14)
- tests de déploiement automatisé
## 1.4.4 (2025-10-11)
- tests de déploiement automatisé
## 1.4.3 (2025-09-15)
- correction de l'affichage du menu en cas de nouveau rapport
- utilisation de css pure plutôt que d'une image pour les notifs de messages
## 1.4.2 (2025-09-14) ## 1.4.2 (2025-09-14)
- annulation de la suppression des tours drapeaux (car impossible de réduire l'écran correctement) - annulation de la suppression des tours drapeaux (car impossible de réduire l'écran correctement)

14
Makefile Normal file
View File

@@ -0,0 +1,14 @@
build:
web-ext build --overwrite-dest
lint:
web-ext lint
deploy_chrome:
chrome-webstore-upload
deploy_firefox:
web-ext sign --channel listed --amo-metadata metadata.json
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path fill="#ff0000" d="M64 320C64 178.6 178.6 64 320 64C461.4 64 576 178.6 576 320C576 461.4 461.4 576 320 576C178.6 576 64 461.4 64 320z"/></svg>

Before

Width:  |  Height:  |  Size: 362 B

View File

@@ -1,36 +1,42 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "KAplus", "name": "KAplus",
"version": "1.4.2", "version": "1.5.1",
"author": "Samuel Campos - netoik.io", "author": "Samuel Campos - netoik.io",
"description": "Extension développée pour améliorer l'expérience de jeu KingsAge (fonctionne avec ou sans premium)", "description": "Extension développée pour améliorer l'expérience de jeu KingsAge (fonctionne avec ou sans premium)",
"browser_specific_settings": { "browser_specific_settings": {
"gecko": { "gecko": {
"id": "{e750d6a9-86ff-4129-aed6-542de03deb79}" "id": "{e750d6a9-86ff-4129-aed6-542de03deb79}",
} "data_collection_permissions": {
}, "required": [
"websiteContent",
"websiteActivity"
]
}
}
},
"content_scripts": [ "content_scripts": [
{ {
"matches": ["https://*.kingsage.gameforge.com/*"], "matches": ["https://*.kingsage.gameforge.com/*"],
"js": ["src/kaplus.js"], "js": ["src/kaplus.js"],
"css": ["src/kaplus.css"] "css": ["src/kaplus.css"]
} }
], ],
"web_accessible_resources": [ "web_accessible_resources": [
{ {
"matches": ["https://*.kingsage.gameforge.com/*"], "matches": ["https://*.kingsage.gameforge.com/*"],
"resources": ["images/*.svg"] "resources": ["images/*.svg"]
} }
], ],
"icons": { "icons": {
"32": "icons/kaplus32.png", "32": "icons/kaplus32.png",
"64": "icons/kaplus64.png", "64": "icons/kaplus64.png",
"100": "icons/kaplus.png", "100": "icons/kaplus.png",
"128": "icons/kaplus128.png" "128": "icons/kaplus128.png"
} }
} }

12
metadata.json Normal file
View File

@@ -0,0 +1,12 @@
{
"version": {
"compatibility": [
"android",
"firefox"
],
"release_notes": {
"fr": "- fonctionnalité de multi-attaques dans la même seconde",
"en-US": "- feature multi-attack in same second"
}
}
}

View File

@@ -52,13 +52,14 @@
opacity: 1; opacity: 1;
} }
a.has_notif::after { a.has_notif::after {
background-image: url("moz-extension://__MSG_@@extension_id__/images/notif.svg"), url("chrome-extension://__MSG_@@extension_id__/images/notif.svg");
background-size: 13px 13px; background-size: 13px 13px;
background-color: #FF0000;
border-radius: 50%;
position: absolute; position: absolute;
top: -13px; top: -13px;
right: -3px; right: 3px;
width: 13px; width: 12px;
height: 13px; height: 12px;
content: ""; content: "";
} }
.shortcut_element_image { .shortcut_element_image {

View File

@@ -3,15 +3,15 @@ function num(s) {
} }
function str(n) { function str(n) {
if (n == 0) { if (n === 0) {
return "0"; return "0";
} }
s = ""; let s = "";
while (n > 0) { while (n > 0) {
if (s != "") { if (s !== "") {
s = "." + s; s = "." + s;
} }
r = n % 1000; let r = n % 1000;
s = r.toString().padStart(3, "0") + s; s = r.toString().padStart(3, "0") + s;
n = ~~(n/1000); n = ~~(n/1000);
} }
@@ -19,51 +19,58 @@ function str(n) {
} }
function createRow(key, value) { function createRow(key, value) {
keyCell = document.createElement("td"); let keyCell = document.createElement("td");
keyCell.textContent = key; keyCell.textContent = key;
valueCell = document.createElement("td");
valueCell.textContent = value; let valueCell = document.createElement("td");
row = document.createElement("tr"); valueCell.textContent = value;
row.appendChild(keyCell);
row.appendChild(valueCell); let row = document.createElement("tr");
return row; row.appendChild(keyCell);
row.appendChild(valueCell);
return row;
} }
function shortcutElementReplace(elt, img, text) { function shortcutElementReplace(elt, img, text) {
imgElements = elt.getElementsByTagName("img") // If more than one hyperlink element found,
for (i=0; i<imgElements.length; i++) { // then keep the last one but with href of the first one.
if (i == 0) { let aElements = elt.getElementsByTagName("a");
elt.getElementsByTagName("a")[0].classList.add("has_notif"); let imgElements = elt.getElementsByTagName("img");
} if (aElements.length > 1 || imgElements.length > 0) {
imgElements[i].remove(); aElements[aElements.length - 1].classList.add("has_notif");
i --; aElements[aElements.length - 1].setAttribute("href", aElements[0].getAttribute("href"));
} for (let i = imgElements.length - 1; i >= 0; i--) {
imgElements[i].remove();
}
for (let i = aElements.length - 2; i >= 0; i--) {
aElements[i].remove();
}
}
spanImageElement = document.createElement("span"); let spanImageElement = document.createElement("span");
spanImageElement.classList.add("shortcut_element_image"); spanImageElement.classList.add("shortcut_element_image");
imgElement = document.createElement("img"); let imgElement = document.createElement("img");
imgElement.setAttribute("src", chrome.runtime.getURL("images/"+img+".svg")); imgElement.setAttribute("src", chrome.runtime.getURL("images/" + img + ".svg"));
spanImageElement.appendChild(imgElement); spanImageElement.appendChild(imgElement);
hyperlinkElement = elt.getElementsByTagName("a")[0]; aElements[0].textContent = "";
hyperlinkElement.textContent = ""; aElements[0].appendChild(spanImageElement);
hyperlinkElement.appendChild(spanImageElement);
if (text) { if (text) {
spanDescElement = document.createElement("span"); let spanDescElement = document.createElement("span");
spanDescElement.classList.add("shortcut_element_desc"); spanDescElement.classList.add("shortcut_element_desc");
spanDescElement.textContent = text; spanDescElement.textContent = text;
hyperlinkElement.appendChild(spanDescElement); aElements[0].appendChild(spanDescElement);
} }
} }
/* Improve main menu display */ /* Improve main menu display */
layCastleTopElements = document.getElementsByClassName("lay_castle_top"); let layCastleTopElements = document.getElementsByClassName("lay_castle_top");
if (layCastleTopElements.length == 1) { if (layCastleTopElements.length === 1) {
document.getElementById("banner_skyscraper").remove(); document.getElementById("banner_skyscraper").remove();
shortcutElements = layCastleTopElements[0].getElementsByClassName("shortcut_element"); let shortcutElements = layCastleTopElements[0].getElementsByClassName("shortcut_element");
shortcutElementReplace(shortcutElements[0], "ranking", shortcutElements[0].textContent.replace(/[^0-9]/g, "")); shortcutElementReplace(shortcutElements[0], "ranking", shortcutElements[0].textContent.replace(/[^0-9]/g, ""));
shortcutElementReplace(shortcutElements[1], "ally", ""); shortcutElementReplace(shortcutElements[1], "ally", "");
shortcutElementReplace(shortcutElements[2], "profile", ""); shortcutElementReplace(shortcutElements[2], "profile", "");
@@ -72,54 +79,95 @@ if (layCastleTopElements.length == 1) {
shortcutElementReplace(shortcutElements[5], "tools", ""); shortcutElementReplace(shortcutElements[5], "tools", "");
shortcutElementReplace(shortcutElements[6], "favorites", ""); shortcutElementReplace(shortcutElements[6], "favorites", "");
shortcutContainers = layCastleTopElements[0].getElementsByClassName("shortcut_container"); let shortcutContainers = layCastleTopElements[0].getElementsByClassName("shortcut_container");
shortcutContainers[0].classList.add("shortcut_container_left"); shortcutContainers[0].classList.add("shortcut_container_left");
shortcutContainers[2].classList.add("shortcut_container_right"); shortcutContainers[2].classList.add("shortcut_container_right");
} }
/* Display unit-points on user profile */ /* Display unit-points on user profile */
if (document.body.id === "info_player") { if (document.body.id === "info_player") {
mainContentPane = document.getElementsByClassName("contentpane")[1]; let mainContentPane = document.getElementsByClassName("contentpane")[1];
borderLists = mainContentPane.getElementsByClassName("borderlist"); let borderLists = mainContentPane.getElementsByClassName("borderlist");
playerPropertiesTable = borderLists[0]; let playerPropertiesTable = borderLists[0];
playerPropertiesRows = playerPropertiesTable.getElementsByTagName("tr"); let playerPropertiesRows = playerPropertiesTable.getElementsByTagName("tr");
totalPoints = num(playerPropertiesRows[2].getElementsByTagName("td")[1].textContent); let totalPoints = num(playerPropertiesRows[2].getElementsByTagName("td")[1].textContent);
villagesCount = num(playerPropertiesRows[4].getElementsByTagName("td")[1].textContent); let villagesCount = num(playerPropertiesRows[4].getElementsByTagName("td")[1].textContent);
villagesTable = borderLists[1]; let villagesTable = borderLists[1];
villagesRows = villagesTable.getElementsByTagName("tr"); let villagesRows = villagesTable.getElementsByTagName("tr");
villagesPoints = 0; let villagesPoints = 0;
for (i=1; i<villagesRows.length; i+=1) { for (let i=1; i<villagesRows.length; i+=1) {
villagesPoints += num(villagesRows[i].getElementsByTagName("td")[2].textContent); villagesPoints += num(villagesRows[i].getElementsByTagName("td")[2].textContent);
} }
villagesBonus = 2250 * Math.max(0, villagesCount - 1); let villagesBonus = 2250 * Math.max(0, villagesCount - 1);
armyPoints = totalPoints - villagesPoints - villagesBonus; let armyPoints = totalPoints - villagesPoints - villagesBonus;
let armyPercent = "-";
if (villagesCount > 0) { if (villagesCount > 0) {
armyPercent = (Math.round(armyPoints / villagesCount) / 100).toString() + " %"; armyPercent = (Math.round(armyPoints / villagesCount) / 100).toString() + " %";
} else {
armyPercent = "-";
} }
playerPropertiesTable.appendChild(createRow("Points troupes:", str(armyPoints))); playerPropertiesTable.appendChild(createRow("Points troupes:", str(armyPoints)));
playerPropertiesTable.appendChild(createRow("% points troupes:", armyPercent)); playerPropertiesTable.appendChild(createRow("% points troupes:", armyPercent));
} }
/* Display unit-points on village overview */ /* Display unit-points on village overview */
if (document.body.id === "overview") { if (document.body.id === "overview") {
settlements = document.getElementById("settlement").textContent.split("|"); let settlements = document.getElementById("settlement").textContent.split("|");
noborderRows = document.getElementsByClassName("noborder"); let noBorderRows = document.getElementsByClassName("noborder");
for (i=0; i<noborderRows.length; i++) { let villagePointsRow = noBorderRows[0];
if (noborderRows[i].textContent.startsWith("Points:")) { for (let i=0; i<noBorderRows.length; i++) {
villagePointsRow = noborderRows[i]; if (noBorderRows[i].textContent.startsWith("Points:")) {
villagePointsRow = noBorderRows[i];
break; break;
} }
} }
unitPointsRow = villagePointsRow.cloneNode(true); let unitPointsRow = villagePointsRow.cloneNode(true);
villagePointsRow.getElementsByTagName("td")[1].textContent = "Points village: " + settlements[3]; villagePointsRow.getElementsByTagName("td")[1].textContent = "Points village: " + settlements[3];
unitPointsRow.getElementsByTagName("td")[1].textContent = "Points troupes: " + settlements[4]; unitPointsRow.getElementsByTagName("td")[1].textContent = "Points troupes: " + settlements[4];
villagePointsRow.after(unitPointsRow); villagePointsRow.after(unitPointsRow);
} }
/* Allow multiple attacks */
if (document.body.id === "build_barracks_command") {
let table = document.createElement("table");
table.classList.add("borderlist");
let tbody = document.createElement("tbody");
let tr = document.createElement("tr");
let th = document.createElement("th");
th.textContent = "Nombre d'attaques:";
tr.appendChild(th)
let td = document.createElement("td");
let input = document.createElement("input");
input.setAttribute("type", "number");
input.setAttribute("name", "attack_count");
input.setAttribute("value", "1");
td.appendChild(input);
tr.appendChild(td);
tbody.appendChild(tr);
table.appendChild(tbody);
let form = document.getElementsByTagName("form")[0];
let firstInput = form.getElementsByTagName("input")[0];
form.insertBefore(table, firstInput);
form.addEventListener("submit", function(event) {
event.preventDefault();
let formData = new FormData(this);
let attackCount = parseInt(formData.get("attack_count").toString());
formData.delete("attack_count");
let sent = 0;
for (let i = 0; i < attackCount; i ++) {
let xhr = new XMLHttpRequest();
xhr.onload = function() {
sent ++;
if (sent === attackCount) {
window.location.replace(xhr.responseURL);
}
}
xhr.open(this.method, this.action, true);
xhr.send(formData);
}
});
}