Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/UpdateVersion.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
pull-requests: write
contents: write
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'github-actions[bot]'
if: github.event.pull_request.head.repo.full_name == github.repository && !endsWith(github.actor, '[bot]')
steps:
- name: Generate a token
id: generate_token
Expand All @@ -26,4 +26,4 @@ jobs:
- name: Update version
env:
PR_BODY: ${{ github.event.pull_request.body }}
run: node ./Update/UpdateVersion.js ${{ steps.generate_token.outputs.token }} ${{ github.event.number }} "${{ github.event.pull_request.title }}" "$PR_BODY"
run: node ./Update/UpdateVersion.js ${{ steps.generate_token.outputs.token }} ${{ github.event.number }} "${{ github.event.pull_request.title }}" "$PR_BODY" "${{ github.event.action }}"
22 changes: 22 additions & 0 deletions Update.json
Original file line number Diff line number Diff line change
Expand Up @@ -3385,6 +3385,28 @@
}
],
"Notes": "No release notes were provided for this release."
},
"3.2.1": {
"UpdateDate": 1771740586846,
"Prerelease": true,

@cubic-dev-ai cubic-dev-ai Bot Feb 27, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Production releases should set "Prerelease" to false. This entry marks 3.2.2 as a prerelease, which will mislabel the production release.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Update.json, line 3391:

<comment>Production releases should set "Prerelease" to false. This entry marks 3.2.2 as a prerelease, which will mislabel the production release.</comment>

<file context>
@@ -3385,6 +3385,28 @@
+        },
+        "3.2.1": {
+            "UpdateDate": 1771740586846,
+            "Prerelease": true,
+            "UpdateContents": [
+                {
</file context>
Suggested change
"Prerelease": true,
"Prerelease": false,
Fix with Cubic

"UpdateContents": [
{
"PR": 916,
"Description": "Fix contest ranking table styling for dark mode"
}
],
"Notes": "Fix contest ranking table colors in dark mode (contestrank-oi.php and contestrank-correct.php)"
},
"3.2.2": {
"UpdateDate": 1771848993140,
"Prerelease": true,
"UpdateContents": [
{
"PR": 919,
"Description": "Gate WebSocket toast notifications by per-feature popup settings"
}
],
"Notes": "Fix WebSocket notification toasts ignoring per-feature popup settings (BBSPopup/MessagePopup)."
}
}
}
7 changes: 6 additions & 1 deletion Update/UpdateVersion.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ execSync("gh pr checkout " + PRNumber);
console.info("PR #" + PRNumber + " has been checked out.");

// Check if the last commit was made by github-actions[bot]
// Only skip for synchronize events (push-triggered) to prevent infinite loops.
// For edited events (PR title/body changes), allow metadata updates even when
// the branch tip is a bot commit.
const eventAction = String(process.argv[6] || "");
const lastCommitAuthor = execSync("git log -1 --pretty=format:'%an'").toString().trim();
console.log("Last commit author: " + lastCommitAuthor);
if (lastCommitAuthor === "github-actions[bot]") {
console.log("Event action : " + eventAction);
if (lastCommitAuthor === "github-actions[bot]" && eventAction !== "edited") {

@cubic-dev-ai cubic-dev-ai Bot Feb 27, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new skip condition contradicts the comment and still blocks non-"edited" actions like opened/reopened. If the intent is to skip only on push-triggered synchronize events, this should explicitly check for synchronize instead of !== "edited" so metadata updates aren’t skipped for other actions.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Update/UpdateVersion.js, line 18:

<comment>The new skip condition contradicts the comment and still blocks non-"edited" actions like `opened`/`reopened`. If the intent is to skip only on push-triggered `synchronize` events, this should explicitly check for `synchronize` instead of `!== "edited"` so metadata updates aren’t skipped for other actions.</comment>

<file context>
@@ -8,9 +8,14 @@ execSync("gh pr checkout " + PRNumber);
 console.log("Last commit author: " + lastCommitAuthor);
-if (lastCommitAuthor === "github-actions[bot]") {
+console.log("Event action       : " + eventAction);
+if (lastCommitAuthor === "github-actions[bot]" && eventAction !== "edited") {
     console.log("Last commit was made by github-actions[bot]. Skipping to prevent infinite loop.");
     process.exit(0);
</file context>
Suggested change
if (lastCommitAuthor === "github-actions[bot]" && eventAction !== "edited") {
if (lastCommitAuthor === "github-actions[bot]" && eventAction === "synchronize") {
Fix with Cubic

console.log("Last commit was made by github-actions[bot]. Skipping to prevent infinite loop.");
process.exit(0);
}
Expand Down
65 changes: 49 additions & 16 deletions XMOJ.user.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ==UserScript==
// @name XMOJ
// @version 3.2.0
// @version 3.2.2
// @description XMOJ增强脚本
// @author @XMOJ-Script-dev, @langningchen and the community
// @namespace https://github/langningchen
Expand Down Expand Up @@ -650,11 +650,13 @@ function HandleNotificationMessage(event) {
console.log("WebSocket: Server confirmed connection at timestamp", notification.timestamp);
}
} else if (notification.type === 'bbs_mention') {
// Backend now provides all data needed for immediate display
CreateAndShowBBSMentionToast(notification.data);
if (UtilityEnabled("BBSPopup")) {
CreateAndShowBBSMentionToast(notification.data);
}
} else if (notification.type === 'mail_mention') {
// Backend now provides all data needed for immediate display
CreateAndShowMailMentionToast(notification.data);
if (UtilityEnabled("MessagePopup")) {
CreateAndShowMailMentionToast(notification.data);
}
} else if (notification.type === 'pong') {
if (UtilityEnabled("DebugMode")) {
console.log("WebSocket: Received pong");
Expand Down Expand Up @@ -2994,11 +2996,21 @@ async function main() {
document.querySelector("#rank").innerText = "比赛暂时还没有排名";
} else {
document.querySelector("body > div > div.mt-3 > center > h3").innerText = document.querySelector("body > div > div.mt-3 > center > h3").innerText.substring(document.querySelector("body > div > div.mt-3 > center > h3").innerText.indexOf(" -- ") + 4) + "(OI排名)";
document.querySelector("#rank > thead > tr > :nth-child(1)").innerText = "排名";
document.querySelector("#rank > thead > tr > :nth-child(2)").innerText = "用户";
document.querySelector("#rank > thead > tr > :nth-child(3)").innerText = "昵称";
document.querySelector("#rank > thead > tr > :nth-child(4)").innerText = "AC数";
document.querySelector("#rank > thead > tr > :nth-child(5)").innerText = "得分";
let HeaderCells = document.querySelectorAll("#rank > thead > tr > *");
HeaderCells[0].innerText = "排名";
HeaderCells[1].innerText = "用户";
HeaderCells[2].innerText = "昵称";
HeaderCells[3].innerText = "AC数";
HeaderCells[4].innerText = "得分";
for (let j = 0; j < HeaderCells.length; j++) {
HeaderCells[j].removeAttribute("bgcolor");
HeaderCells[j].style.setProperty("background-color", "black", "important");
HeaderCells[j].style.setProperty("color", "white", "important");
let Links = HeaderCells[j].querySelectorAll("a");
for (let k = 0; k < Links.length; k++) {
Links[k].style.setProperty("color", "white", "important");
}
}
let RefreshOIRank = async () => {
await fetch(location.href)
.then((Response) => {
Expand All @@ -3009,6 +3021,7 @@ async function main() {
TidyTable(ParsedDocument.getElementById("rank"));
let Temp = ParsedDocument.getElementById("rank").rows;
for (var i = 1; i < Temp.length; i++) {
Temp[i].style.backgroundColor = "";
let MetalCell = Temp[i].cells[0];
let Metal = document.createElement("span");
Metal.innerText = MetalCell.innerText;
Expand All @@ -3018,6 +3031,10 @@ async function main() {
GetUsernameHTML(Temp[i].cells[1], Temp[i].cells[1].innerText);
Temp[i].cells[2].innerHTML = Temp[i].cells[2].innerText;
Temp[i].cells[3].innerHTML = Temp[i].cells[3].innerText;
for (let j = 0; j < 5 && j < Temp[i].cells.length; j++) {
Temp[i].cells[j].style.backgroundColor = "";
Temp[i].cells[j].style.color = "";
}
for (let j = 5; j < Temp[i].cells.length; j++) {
let InnerText = Temp[i].cells[j].innerText;
let BackgroundColor = Temp[i].cells[j].style.backgroundColor;
Expand All @@ -3038,7 +3055,7 @@ async function main() {
} else if (FirstBlood) {
BackgroundColor = "rgb(127, 127, 255)";
} else if (Solved) {
BackgroundColor = "rgb(0, 255, 0, " + Math.max(1 / 10 * (10 - ErrorCount), 0.2) + ")";
BackgroundColor = "rgba(0, 255, 0, " + Math.max(1 / 10 * (10 - ErrorCount), 0.2) + ")";
if (ErrorCount != 0) {
InnerText += " (" + (ErrorCount == 5 ? "4+" : ErrorCount) + ")";
}
Expand Down Expand Up @@ -3080,11 +3097,21 @@ async function main() {
document.querySelector("body > div > div.mt-3 > center > h3").innerText = document.querySelector("body > div > div.mt-3 > center > h3").innerText.substring(document.querySelector("body > div > div.mt-3 > center > h3").innerText.indexOf(" -- ") + 4) + "(订正排名)";
document.querySelector("body > div > div.mt-3 > center > a").remove();
}
document.querySelector("#rank > thead > tr > :nth-child(1)").innerText = "排名";
document.querySelector("#rank > thead > tr > :nth-child(2)").innerText = "用户";
document.querySelector("#rank > thead > tr > :nth-child(3)").innerText = "昵称";
document.querySelector("#rank > thead > tr > :nth-child(4)").innerText = "AC数";
document.querySelector("#rank > thead > tr > :nth-child(5)").innerText = "得分";
let HeaderCells = document.querySelectorAll("#rank > thead > tr > *");
HeaderCells[0].innerText = "排名";
HeaderCells[1].innerText = "用户";
HeaderCells[2].innerText = "昵称";
HeaderCells[3].innerText = "AC数";
HeaderCells[4].innerText = "得分";
for (let j = 0; j < HeaderCells.length; j++) {
HeaderCells[j].removeAttribute("bgcolor");
HeaderCells[j].style.setProperty("background-color", "black", "important");
HeaderCells[j].style.setProperty("color", "white", "important");
let Links = HeaderCells[j].querySelectorAll("a");
for (let k = 0; k < Links.length; k++) {
Links[k].style.setProperty("color", "white", "important");
}
}
let RefreshCorrectRank = async () => {
await fetch(location.href)
.then((Response) => {
Expand All @@ -3095,6 +3122,7 @@ async function main() {
TidyTable(ParsedDocument.getElementById("rank"));
let Temp = ParsedDocument.getElementById("rank").rows;
for (var i = 1; i < Temp.length; i++) {
Temp[i].style.backgroundColor = "";
let MetalCell = Temp[i].cells[0];
let Metal = document.createElement("span");
Metal.innerText = MetalCell.innerText;
Expand All @@ -3104,6 +3132,10 @@ async function main() {
GetUsernameHTML(Temp[i].cells[1], Temp[i].cells[1].innerText);
Temp[i].cells[2].innerHTML = Temp[i].cells[2].innerText;
Temp[i].cells[3].innerHTML = Temp[i].cells[3].innerText;
for (let j = 0; j < 5 && j < Temp[i].cells.length; j++) {
Temp[i].cells[j].style.backgroundColor = "";
Temp[i].cells[j].style.color = "";
}
for (let j = 5; j < Temp[i].cells.length; j++) {
let InnerText = Temp[i].cells[j].innerText;
let BackgroundColor = Temp[i].cells[j].style.backgroundColor;
Expand Down Expand Up @@ -3136,6 +3168,7 @@ async function main() {
}
Temp[i].cells[j].innerHTML = InnerText;
Temp[i].cells[j].style.backgroundColor = BackgroundColor;
Temp[i].cells[j].style.color = (UtilityEnabled("DarkMode") ? "white" : "black");
}
}
document.querySelector("#rank > tbody").innerHTML = ParsedDocument.querySelector("#rank > tbody").innerHTML;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "xmoj-script",
"version": "3.2.0",
"version": "3.2.2",

@cubic-dev-ai cubic-dev-ai Bot Feb 27, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Manual version bump in package.json violates the automated versioning workflow and risks desynchronizing versions. Revert the manual change and let UpdateVersion.js handle version updates.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At package.json, line 3:

<comment>Manual version bump in package.json violates the automated versioning workflow and risks desynchronizing versions. Revert the manual change and let UpdateVersion.js handle version updates.</comment>

<file context>
@@ -1,6 +1,6 @@
 {
   "name": "xmoj-script",
-  "version": "3.2.0",
+  "version": "3.2.2",
   "description": "an improvement script for xmoj.tech",
   "main": "AddonScript.js",
</file context>
Fix with Cubic

"description": "an improvement script for xmoj.tech",
"main": "AddonScript.js",
"scripts": {
Expand Down
Loading