From 5828cf4c33a54d6e64f8c9c18c58797b4ba55d1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 01:04:31 +0000 Subject: [PATCH 01/43] Bump actions/create-github-app-token from 2 to 3 Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 2 to 3. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/AutoLabelIssue.yml | 2 +- .github/workflows/AutoLablePR.yml | 2 +- .github/workflows/Daily.yml | 2 +- .github/workflows/Prerelease.yml | 2 +- .github/workflows/Release.yml | 2 +- .github/workflows/UpdateVersion.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/AutoLabelIssue.yml b/.github/workflows/AutoLabelIssue.yml index 58ccb0494..2c4bace88 100644 --- a/.github/workflows/AutoLabelIssue.yml +++ b/.github/workflows/AutoLabelIssue.yml @@ -14,7 +14,7 @@ jobs: fetch-depth: 0 - name: Generate a token id: generate_token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/AutoLablePR.yml b/.github/workflows/AutoLablePR.yml index cb6a4abf8..1c5f05a05 100644 --- a/.github/workflows/AutoLablePR.yml +++ b/.github/workflows/AutoLablePR.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Generate a token id: generate_token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/Daily.yml b/.github/workflows/Daily.yml index a4695afee..da5218d35 100644 --- a/.github/workflows/Daily.yml +++ b/.github/workflows/Daily.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Generate a token id: generate_token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/Prerelease.yml b/.github/workflows/Prerelease.yml index 387437f08..ec92742ce 100644 --- a/.github/workflows/Prerelease.yml +++ b/.github/workflows/Prerelease.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Generate a token id: generate_token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index e9c591396..8dedca9a8 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Generate a token id: generate_token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/UpdateVersion.yml b/.github/workflows/UpdateVersion.yml index 6112841f7..e43ba0c82 100644 --- a/.github/workflows/UpdateVersion.yml +++ b/.github/workflows/UpdateVersion.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Generate a token id: generate_token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} From 32ab5602da4c14d7e09216779e1e1ae611cfc9eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 01:33:44 +0000 Subject: [PATCH 02/43] Initial plan From ba982dd7c1e9fcd613e23d171566f058107b9355 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 01:41:56 +0000 Subject: [PATCH 03/43] feat: Add cross-device settings sync via GetUserSettings/SetUserSettings API Agent-Logs-Url: https://github.com/XMOJ-Script-dev/XMOJ-Script/sessions/9b7ffa1a-8077-4f56-aac3-e85b3ec4876c Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com> --- XMOJ.user.js | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index 19f60be84..654fe433d 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -532,6 +532,26 @@ let RequestAPI = (Action, Data, CallBack) => { } } }; +let SyncSettingsToCloud = (CallBack) => { + if (!CurrentUsername) return; + let Settings = {}; + for (let i = 0; i < localStorage.length; i++) { + let key = localStorage.key(i); + if (key && key.startsWith("UserScript-Setting-")) { + Settings[key.replace("UserScript-Setting-", "")] = localStorage.getItem(key); + } + } + RequestAPI("SetUserSettings", {"Settings": JSON.stringify(Settings)}, (Response) => { + if (UtilityEnabled("DebugMode")) { + if (Response.Success) { + console.log("设置已同步到云端"); + } else { + console.error("设置云端同步失败:", Response.Message); + } + } + if (CallBack) CallBack(Response); + }); +}; unsafeWindow.GetContestProblemList = async function(RefreshList) { try { @@ -2127,6 +2147,7 @@ async function main() { Select.addEventListener("change", () => { localStorage.setItem("UserScript-Setting-Theme", Select.value); initTheme(); + SyncSettingsToCloud(); }); Row.appendChild(Select); } else if (Data[i].Children == undefined) { @@ -2144,7 +2165,8 @@ async function main() { CheckBox.checked = true; } CheckBox.addEventListener("change", () => { - return localStorage.setItem("UserScript-Setting-" + Data[i].ID, CheckBox.checked); + localStorage.setItem("UserScript-Setting-" + Data[i].ID, CheckBox.checked); + SyncSettingsToCloud(); }); Row.appendChild(CheckBox); @@ -2236,6 +2258,79 @@ async function main() { UtilitiesCardBody.appendChild(UtilitiesCardFooter); UtilitiesCard.appendChild(UtilitiesCardBody); Container.appendChild(UtilitiesCard); + let SyncCard = document.createElement("div"); + SyncCard.className = "card mb-3"; + let SyncCardHeader = document.createElement("div"); + SyncCardHeader.className = "card-header"; + SyncCardHeader.innerText = "设置云同步"; + SyncCard.appendChild(SyncCardHeader); + let SyncCardBody = document.createElement("div"); + SyncCardBody.className = "card-body"; + let SyncStatusText = document.createElement("p"); + SyncStatusText.className = "card-text mb-2"; + SyncStatusText.id = "UserScript-SyncStatus"; + SyncStatusText.innerText = "正在从云端加载设置…"; + SyncCardBody.appendChild(SyncStatusText); + let SyncButtonGroup = document.createElement("div"); + SyncButtonGroup.className = "d-flex gap-2"; + let ApplyCloudSettings = (cloudSettings) => { + for (let key in cloudSettings) { + localStorage.setItem("UserScript-Setting-" + key, cloudSettings[key]); + if (key === "Theme") { + let themeSelect = document.getElementById("UserScript-Setting-Theme"); + if (themeSelect) themeSelect.value = cloudSettings[key]; + initTheme(); + } else { + let checkbox = document.getElementById(key); + if (checkbox) checkbox.checked = (cloudSettings[key] === "true"); + } + } + }; + let UploadBtn = document.createElement("button"); + UploadBtn.className = "btn btn-sm btn-primary"; + UploadBtn.innerText = "上传设置到云端"; + UploadBtn.addEventListener("click", () => { + SyncStatusText.innerText = "正在上传…"; + SyncSettingsToCloud((Response) => { + SyncStatusText.innerText = Response.Success ? "上传成功" : ("上传失败: " + Response.Message); + }); + }); + SyncButtonGroup.appendChild(UploadBtn); + let DownloadBtn = document.createElement("button"); + DownloadBtn.className = "btn btn-sm btn-secondary"; + DownloadBtn.innerText = "从云端下载设置"; + DownloadBtn.addEventListener("click", () => { + SyncStatusText.innerText = "正在下载…"; + RequestAPI("GetUserSettings", {}, (Response) => { + if (Response.Success) { + ApplyCloudSettings(Response.Data.Settings); + SyncStatusText.innerText = "下载成功,设置已应用(部分设置需刷新页面后生效)"; + } else { + SyncStatusText.innerText = "下载失败: " + Response.Message; + } + }); + }); + SyncButtonGroup.appendChild(DownloadBtn); + SyncCardBody.appendChild(SyncButtonGroup); + SyncCard.appendChild(SyncCardBody); + Container.appendChild(SyncCard); + RequestAPI("GetUserSettings", {}, (Response) => { + let SyncStatusEl = document.getElementById("UserScript-SyncStatus"); + if (Response.Success) { + let cloudSettings = Response.Data.Settings; + if (Object.keys(cloudSettings).length === 0) { + if (SyncStatusEl) SyncStatusEl.innerText = "正在上传本地设置至云端…"; + SyncSettingsToCloud((Resp) => { + if (SyncStatusEl) SyncStatusEl.innerText = Resp.Success ? "已将本地设置上传至云端" : ("上传失败: " + Resp.Message); + }); + } else { + ApplyCloudSettings(cloudSettings); + if (SyncStatusEl) SyncStatusEl.innerText = "已从云端加载设置"; + } + } else { + if (SyncStatusEl) SyncStatusEl.innerText = "云端设置加载失败: " + Response.Message; + } + }); let FeedbackCard = document.createElement("div"); FeedbackCard.className = "card mb-3"; let FeedbackCardHeader = document.createElement("div"); From d379b84eab2ed6feb23000fca61042646c6ef14a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 02:02:11 +0000 Subject: [PATCH 04/43] 3.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 86a7ba561..b6f88c0db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.4.0", + "version": "3.4.1", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From a7832e959ecb062df7780130bee667e0b7016ed8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 02:02:16 +0000 Subject: [PATCH 05/43] Update version info to 3.4.1 --- Update.json | 11 +++++++++++ XMOJ.user.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 8fb7414c5..df9037fd6 100644 --- a/Update.json +++ b/Update.json @@ -3519,6 +3519,17 @@ } ], "Notes": "No release notes were provided for this release." + }, + "3.4.1": { + "UpdateDate": 1774663331441, + "Prerelease": true, + "UpdateContents": [ + { + "PR": 961, + "Description": "[WIP] Add cross-device sync for user settings" + } + ], + "Notes": "No release notes were provided for this release." } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index 654fe433d..d3842dd5f 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.4.0 +// @version 3.4.1 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen From c0bee337a7cc4beb232f173da1cb7fbfa2f51df9 Mon Sep 17 00:00:00 2001 From: Shan Wenxiao Date: Sat, 28 Mar 2026 10:07:13 +0800 Subject: [PATCH 06/43] fix bug risk of null fallback Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> Signed-off-by: Shan Wenxiao --- XMOJ.user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index d3842dd5f..0711d888b 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -2317,7 +2317,7 @@ async function main() { RequestAPI("GetUserSettings", {}, (Response) => { let SyncStatusEl = document.getElementById("UserScript-SyncStatus"); if (Response.Success) { - let cloudSettings = Response.Data.Settings; + const cloudSettings = (Response.Data && Response.Data.Settings) || {}; if (Object.keys(cloudSettings).length === 0) { if (SyncStatusEl) SyncStatusEl.innerText = "正在上传本地设置至云端…"; SyncSettingsToCloud((Resp) => { From fce1d3fafd106aa27ee8d989628a6f6a42227e1e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 02:07:42 +0000 Subject: [PATCH 07/43] Update time and description of 3.4.1 --- Update.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Update.json b/Update.json index df9037fd6..364000764 100644 --- a/Update.json +++ b/Update.json @@ -3521,12 +3521,12 @@ "Notes": "No release notes were provided for this release." }, "3.4.1": { - "UpdateDate": 1774663331441, + "UpdateDate": 1774663655535, "Prerelease": true, "UpdateContents": [ { "PR": 961, - "Description": "[WIP] Add cross-device sync for user settings" + "Description": "feat: Cross-device settings sync via cloud backend" } ], "Notes": "No release notes were provided for this release." From 09af1fb2e0602c7a8e6281d6d559d2417b65b982 Mon Sep 17 00:00:00 2001 From: Shan Wenxiao Date: Sat, 28 Mar 2026 10:08:26 +0800 Subject: [PATCH 08/43] fix not logged in Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Signed-off-by: Shan Wenxiao --- XMOJ.user.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index 0711d888b..bc0cd2c39 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -533,7 +533,10 @@ let RequestAPI = (Action, Data, CallBack) => { } }; let SyncSettingsToCloud = (CallBack) => { - if (!CurrentUsername) return; + if (!CurrentUsername) { + if (CallBack) CallBack({ Success: false, Message: "用户未登录" }); + return; + } let Settings = {}; for (let i = 0; i < localStorage.length; i++) { let key = localStorage.key(i); From 078ed1bfafc3bf3f7fb59c7bf1412e87fbcab4b3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 02:08:47 +0000 Subject: [PATCH 09/43] Update time and description of 3.4.1 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 364000764..176312e4f 100644 --- a/Update.json +++ b/Update.json @@ -3521,7 +3521,7 @@ "Notes": "No release notes were provided for this release." }, "3.4.1": { - "UpdateDate": 1774663655535, + "UpdateDate": 1774663722058, "Prerelease": true, "UpdateContents": [ { From 43ee3d0ad7ef81902ec1fb9475a58bcbd6d843a7 Mon Sep 17 00:00:00 2001 From: Shan Wenxiao Date: Sat, 28 Mar 2026 10:10:24 +0800 Subject: [PATCH 10/43] fix checkbox Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Shan Wenxiao --- XMOJ.user.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index bc0cd2c39..7f6a615c5 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -2278,14 +2278,18 @@ async function main() { SyncButtonGroup.className = "d-flex gap-2"; let ApplyCloudSettings = (cloudSettings) => { for (let key in cloudSettings) { - localStorage.setItem("UserScript-Setting-" + key, cloudSettings[key]); + const rawValue = cloudSettings[key]; + localStorage.setItem("UserScript-Setting-" + key, String(rawValue)); if (key === "Theme") { let themeSelect = document.getElementById("UserScript-Setting-Theme"); - if (themeSelect) themeSelect.value = cloudSettings[key]; + if (themeSelect) themeSelect.value = String(rawValue); initTheme(); } else { let checkbox = document.getElementById(key); - if (checkbox) checkbox.checked = (cloudSettings[key] === "true"); + if (checkbox) { + const normalizedChecked = (typeof rawValue === "boolean") ? rawValue : (String(rawValue).toLowerCase() === "true"); + checkbox.checked = normalizedChecked; + } } } }; From 332b5e1616430909355e05693e29d233b05900e7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 02:10:45 +0000 Subject: [PATCH 11/43] Update time and description of 3.4.1 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 176312e4f..d1877690a 100644 --- a/Update.json +++ b/Update.json @@ -3521,7 +3521,7 @@ "Notes": "No release notes were provided for this release." }, "3.4.1": { - "UpdateDate": 1774663722058, + "UpdateDate": 1774663840677, "Prerelease": true, "UpdateContents": [ { From 429366171ed144192ce1327aea6cfad6a6301da0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Mar 2026 02:17:21 +0000 Subject: [PATCH 12/43] feat: Add CloudSync setting toggle to control cloud settings sync (default on) Agent-Logs-Url: https://github.com/XMOJ-Script-dev/XMOJ-Script/sessions/91cd1e68-c0d5-495a-bbed-36e3cd49d955 Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com> --- XMOJ.user.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index 7f6a615c5..954fa8616 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -537,6 +537,10 @@ let SyncSettingsToCloud = (CallBack) => { if (CallBack) CallBack({ Success: false, Message: "用户未登录" }); return; } + if (!UtilityEnabled("CloudSync")) { + if (CallBack) CallBack({ Success: false, Message: "云同步已禁用" }); + return; + } let Settings = {}; for (let i = 0; i < localStorage.length; i++) { let key = localStorage.key(i); @@ -2169,7 +2173,10 @@ async function main() { } CheckBox.addEventListener("change", () => { localStorage.setItem("UserScript-Setting-" + Data[i].ID, CheckBox.checked); - SyncSettingsToCloud(); + // Don't sync when disabling CloudSync itself (it's already off) + if (Data[i].ID !== "CloudSync" || CheckBox.checked) { + SyncSettingsToCloud(); + } }); Row.appendChild(CheckBox); @@ -2250,6 +2257,8 @@ async function main() { "ID": "BBSPopup", "Type": "A", "Name": "讨论提醒" }, {"ID": "MessagePopup", "Type": "A", "Name": "短消息提醒"}, { "ID": "ImageEnlarger", "Type": "A", "Name": "图片放大功能" + }, { + "ID": "CloudSync", "Type": "A", "Name": "将设置同步至云端(跨设备同步)" }, { "ID": "DebugMode", "Type": "A", "Name": "调试模式(仅供开发者使用)" }, { @@ -2321,6 +2330,7 @@ async function main() { SyncCardBody.appendChild(SyncButtonGroup); SyncCard.appendChild(SyncCardBody); Container.appendChild(SyncCard); + if (UtilityEnabled("CloudSync")) { RequestAPI("GetUserSettings", {}, (Response) => { let SyncStatusEl = document.getElementById("UserScript-SyncStatus"); if (Response.Success) { @@ -2338,6 +2348,10 @@ async function main() { if (SyncStatusEl) SyncStatusEl.innerText = "云端设置加载失败: " + Response.Message; } }); + } else { + let SyncStatusEl = document.getElementById("UserScript-SyncStatus"); + if (SyncStatusEl) SyncStatusEl.innerText = "云同步已禁用"; + } let FeedbackCard = document.createElement("div"); FeedbackCard.className = "card mb-3"; let FeedbackCardHeader = document.createElement("div"); From 6cc1ca5cd3584eded8b3e8dd44ab38f9c303d1c7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 05:21:26 +0000 Subject: [PATCH 13/43] Update time and description of 3.4.1 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index d1877690a..3c71c0525 100644 --- a/Update.json +++ b/Update.json @@ -3521,7 +3521,7 @@ "Notes": "No release notes were provided for this release." }, "3.4.1": { - "UpdateDate": 1774663840677, + "UpdateDate": 1774675280384, "Prerelease": true, "UpdateContents": [ { From 7f7f08efc3911242d56ebf0153b680bee9fe5bce Mon Sep 17 00:00:00 2001 From: boomzero Date: Sat, 28 Mar 2026 21:33:15 +0800 Subject: [PATCH 14/43] feat: Add hourly periodic cloud settings sync --- XMOJ.user.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/XMOJ.user.js b/XMOJ.user.js index 954fa8616..9798699d8 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -560,6 +560,28 @@ let SyncSettingsToCloud = (CallBack) => { }); }; +let PeriodicCloudSync = () => { + if (!CurrentUsername || !UtilityEnabled("CloudSync")) return; + RequestAPI("GetUserSettings", {}, (Response) => { + if (Response.Success) { + const cloudSettings = (Response.Data && Response.Data.Settings) || {}; + if (Object.keys(cloudSettings).length > 0) { + let themeChanged = false; + for (let key in cloudSettings) { + const rawValue = String(cloudSettings[key]); + const localKey = "UserScript-Setting-" + key; + if (localStorage.getItem(localKey) !== rawValue) { + localStorage.setItem(localKey, rawValue); + if (key === "Theme") themeChanged = true; + } + } + if (themeChanged) initTheme(); + } + } + SyncSettingsToCloud(); + }); +}; + unsafeWindow.GetContestProblemList = async function(RefreshList) { try { const contestReq = await fetch("https://www.xmoj.tech/contest.php?cid=" + SearchParams.get("cid")); @@ -917,6 +939,7 @@ let initTheme = () => { } }; initTheme(); +if (UtilityEnabled("CloudSync")) setInterval(PeriodicCloudSync, 60 * 60 * 1000); class NavbarStyler { From 692f67f85244e59fb1ca115e064729d579ea5d0c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 13:34:59 +0000 Subject: [PATCH 15/43] 3.4.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b6f88c0db..dfcb7f1d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.4.1", + "version": "3.4.2", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From ef9d428fd40341b80401cd7f8bb89db81a356b0c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 13:35:04 +0000 Subject: [PATCH 16/43] Update version info to 3.4.2 --- Update.json | 11 +++++++++++ XMOJ.user.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 3c71c0525..e398fd9fd 100644 --- a/Update.json +++ b/Update.json @@ -3530,6 +3530,17 @@ } ], "Notes": "No release notes were provided for this release." + }, + "3.4.2": { + "UpdateDate": 1774704899385, + "Prerelease": true, + "UpdateContents": [ + { + "PR": 963, + "Description": "feat: Add hourly periodic cloud settings sync" + } + ], + "Notes": "Add hourly automatic cloud settings sync. Every hour, if CloudSync is enabled, settings are downloaded from the cloud and applied locally, then local settings are uploaded to the cloud. This keeps settings in sync across devices without requiring a visit to the settings page." } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index 9798699d8..23a640de5 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.4.1 +// @version 3.4.2 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen From 733ecf7e7858eaa1fc9c94871e7e9337d3331af8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 13:36:15 +0000 Subject: [PATCH 17/43] Update time and description of 3.4.2 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index e398fd9fd..020512b8e 100644 --- a/Update.json +++ b/Update.json @@ -3532,7 +3532,7 @@ "Notes": "No release notes were provided for this release." }, "3.4.2": { - "UpdateDate": 1774704899385, + "UpdateDate": 1774704969242, "Prerelease": true, "UpdateContents": [ { From 2b5fb37a97717d51935db6c3619fcea9ea5073b9 Mon Sep 17 00:00:00 2001 From: boomzero Date: Sat, 28 Mar 2026 21:46:27 +0800 Subject: [PATCH 18/43] fix: Only upload after successful download; always register sync interval --- XMOJ.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index 23a640de5..2e70ed2de 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -577,8 +577,8 @@ let PeriodicCloudSync = () => { } if (themeChanged) initTheme(); } + SyncSettingsToCloud(); } - SyncSettingsToCloud(); }); }; @@ -939,7 +939,7 @@ let initTheme = () => { } }; initTheme(); -if (UtilityEnabled("CloudSync")) setInterval(PeriodicCloudSync, 60 * 60 * 1000); +setInterval(PeriodicCloudSync, 60 * 60 * 1000); class NavbarStyler { From e654ffaaf32cd6f9ceaf9f4643e4a379d02e7027 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 13:47:29 +0000 Subject: [PATCH 19/43] Update time and description of 3.4.2 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 020512b8e..ece12d29d 100644 --- a/Update.json +++ b/Update.json @@ -3532,7 +3532,7 @@ "Notes": "No release notes were provided for this release." }, "3.4.2": { - "UpdateDate": 1774704969242, + "UpdateDate": 1774705643181, "Prerelease": true, "UpdateContents": [ { From 39b16219a31631be76deee82b6ff2962bd2d11c4 Mon Sep 17 00:00:00 2001 From: boomzero Date: Sat, 28 Mar 2026 21:53:59 +0800 Subject: [PATCH 20/43] fix: Use localStorage timestamp to track sync across tabs and page loads --- XMOJ.user.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/XMOJ.user.js b/XMOJ.user.js index 2e70ed2de..4ae52ab66 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -562,8 +562,11 @@ let SyncSettingsToCloud = (CallBack) => { let PeriodicCloudSync = () => { if (!CurrentUsername || !UtilityEnabled("CloudSync")) return; + const lastSync = parseInt(localStorage.getItem("UserScript-CloudSync-LastSync") || "0"); + if (Date.now() - lastSync < 60 * 60 * 1000) return; RequestAPI("GetUserSettings", {}, (Response) => { if (Response.Success) { + localStorage.setItem("UserScript-CloudSync-LastSync", String(Date.now())); const cloudSettings = (Response.Data && Response.Data.Settings) || {}; if (Object.keys(cloudSettings).length > 0) { let themeChanged = false; @@ -939,6 +942,7 @@ let initTheme = () => { } }; initTheme(); +PeriodicCloudSync(); setInterval(PeriodicCloudSync, 60 * 60 * 1000); From 3c7f746303e931ec0cf32f3371b948e63b1cc14e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 28 Mar 2026 13:54:52 +0000 Subject: [PATCH 21/43] Update time and description of 3.4.2 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index ece12d29d..1103a1bd7 100644 --- a/Update.json +++ b/Update.json @@ -3532,7 +3532,7 @@ "Notes": "No release notes were provided for this release." }, "3.4.2": { - "UpdateDate": 1774705643181, + "UpdateDate": 1774706085890, "Prerelease": true, "UpdateContents": [ { From 2db8eceb53bd1de43f747c2cff4c5aa6a7332def Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 02:39:32 +0000 Subject: [PATCH 22/43] refactor: migrate backend calls to /v1 routes Agent-Logs-Url: https://github.com/XMOJ-Script-dev/XMOJ-Script/sessions/606d7c42-f0ad-4d97-80ae-b8d92c2d6725 Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com> --- XMOJ.user.js | 12 ++++++------ messages.html | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index 4ae52ab66..65e95d61f 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -505,7 +505,7 @@ let RequestAPI = (Action, Data, CallBack) => { } GM_xmlhttpRequest({ method: "POST", - url: (UtilityEnabled("SuperDebug") ? "http://127.0.0.1:8787/" : "https://api.xmoj-bbs.me/") + Action, + url: (UtilityEnabled("SuperDebug") ? "http://127.0.0.1:8787/v1/" : "https://api.xmoj-bbs.me/v1/") + Action, headers: { "Content-Type": "application/json", "Cache-Control": "no-cache", @@ -643,7 +643,7 @@ function ConnectNotificationSocket() { return; } - let wsUrl = (UtilityEnabled("SuperDebug") ? "ws://127.0.0.1:8787" : "wss://api.xmoj-bbs.me") + "/ws/notifications?SessionID=" + Session; + let wsUrl = (UtilityEnabled("SuperDebug") ? "ws://127.0.0.1:8787" : "wss://api.xmoj-bbs.me") + "/v1/ws/notifications?SessionID=" + Session; if (UtilityEnabled("DebugMode")) { console.log("WebSocket: Connecting to", wsUrl); @@ -5021,7 +5021,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - Content.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + Content.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; Content.dispatchEvent(new Event("input")); } else { Content.value = Before + `![上传失败!` + ResponseData.Message + `]()` + After; @@ -5277,7 +5277,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentElement.dispatchEvent(new Event("input")); } else { ContentElement.value = Before + `![上传失败!]()` + After; @@ -5450,7 +5450,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentElement.dispatchEvent(new Event("input")); } else { ContentElement.value = Before + `![上传失败!]()` + After; @@ -5708,7 +5708,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentEditor.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentEditor.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentEditor.dispatchEvent(new Event("input")); } else { ContentEditor.value = Before + `![上传失败!]()` + After; diff --git a/messages.html b/messages.html index ea7e2484a..794b2d3f0 100644 --- a/messages.html +++ b/messages.html @@ -367,8 +367,8 @@ 'use strict'; // ── Constants ────────────────────────────────────────────────────────────── -const API_BASE = 'https://api.xmoj-bbs.me/'; -const ASSET_BASE = 'https://assets.xmoj-bbs.me/GetImage?ImageID='; +const API_BASE = 'https://api.xmoj-bbs.me/v1/'; +const ASSET_BASE = 'https://assets.xmoj-bbs.me/v1/GetImage?ImageID='; const XMOJ_BASE = 'https://www.xmoj.tech'; const WEBUI_VERSION = 'webui-1.0.0'; const STORAGE_USER = 'xmoj-msg-username'; From bf675238f0682fffd03ca1b5807d93b9ed1a7dc2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 11 Apr 2026 02:45:49 +0000 Subject: [PATCH 23/43] 3.4.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dfcb7f1d3..244106ae3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.4.2", + "version": "3.4.3", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From cb3db4a9a67de31638d6ba75b3deffe7bc000acc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 11 Apr 2026 02:45:56 +0000 Subject: [PATCH 24/43] Update version info to 3.4.3 --- Update.json | 11 +++++++++++ XMOJ.user.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 1103a1bd7..7e7d1d25b 100644 --- a/Update.json +++ b/Update.json @@ -3541,6 +3541,17 @@ } ], "Notes": "Add hourly automatic cloud settings sync. Every hour, if CloudSync is enabled, settings are downloaded from the cloud and applied locally, then local settings are uploaded to the cloud. This keeps settings in sync across devices without requiring a visit to the settings page." + }, + "3.4.3": { + "UpdateDate": 1775875549804, + "Prerelease": true, + "UpdateContents": [ + { + "PR": 969, + "Description": "Migrate XMOJ-BBS client endpoints to routes" + } + ], + "Notes": "No release notes were provided for this release." } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index 65e95d61f..eecedc5c6 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.4.2 +// @version 3.4.3 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen From 9afb3df53129424f7e795fb32e81f9f381f43d10 Mon Sep 17 00:00:00 2001 From: zsTree Date: Sun, 12 Apr 2026 13:39:12 +0800 Subject: [PATCH 25/43] Update endpoint description in Update.json Signed-off-by: zsTree --- Update.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Update.json b/Update.json index 7e7d1d25b..53e484d43 100644 --- a/Update.json +++ b/Update.json @@ -3548,10 +3548,10 @@ "UpdateContents": [ { "PR": 969, - "Description": "Migrate XMOJ-BBS client endpoints to routes" + "Description": "Migrate XMOJ-BBS client endpoints to /v1 routes" } ], "Notes": "No release notes were provided for this release." } } -} \ No newline at end of file +} From 5c6e3c5c815f1cbcb4a4591fa0273ac28dd266ab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Apr 2026 05:39:38 +0000 Subject: [PATCH 26/43] Update time and description of 3.4.3 --- Update.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Update.json b/Update.json index 53e484d43..d28c065e9 100644 --- a/Update.json +++ b/Update.json @@ -3543,15 +3543,15 @@ "Notes": "Add hourly automatic cloud settings sync. Every hour, if CloudSync is enabled, settings are downloaded from the cloud and applied locally, then local settings are uploaded to the cloud. This keeps settings in sync across devices without requiring a visit to the settings page." }, "3.4.3": { - "UpdateDate": 1775875549804, + "UpdateDate": 1775972372292, "Prerelease": true, "UpdateContents": [ { "PR": 969, - "Description": "Migrate XMOJ-BBS client endpoints to /v1 routes" + "Description": "Migrate XMOJ-BBS client endpoints to routes" } ], "Notes": "No release notes were provided for this release." } } -} +} \ No newline at end of file From c24d3fcdde14dc447af6b0d8703a42dd2b19eba4 Mon Sep 17 00:00:00 2001 From: zsTree Date: Sun, 12 Apr 2026 06:30:42 +0000 Subject: [PATCH 27/43] Fix loginpage.php Loop --- XMOJ.user.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/XMOJ.user.js b/XMOJ.user.js index eecedc5c6..daba8d877 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -911,7 +911,9 @@ GM_registerMenuCommand("重置数据", () => { }); //otherwise CurrentUsername might be undefined +let logined = (document.querySelector('a').innerText == "Please logout First!"); if (UtilityEnabled("AutoLogin") && document.querySelector("body > a:nth-child(1)") != null && document.querySelector("body > a:nth-child(1)").innerText == "请登录后继续操作") { + if (logined) location.href = (localStorage.getItem("UserScript-LastPage") == null ? "/" : localStorage.getItem("UserScript-LastPage")); localStorage.setItem("UserScript-LastPage", location.pathname + location.search); location.href = "https://www.xmoj.tech/loginpage.php"; } @@ -919,6 +921,7 @@ if (UtilityEnabled("AutoLogin") && document.querySelector("body > a:nth-child(1) let SearchParams = new URLSearchParams(location.search); let ServerURL = (UtilityEnabled("DebugMode") ? "https://ghpages.xmoj-bbs.me/" : "https://www.xmoj-bbs.me") if (document.querySelector("#profile") === null) { + if (logined) location.href = (localStorage.getItem("UserScript-LastPage") == null ? "/" : localStorage.getItem("UserScript-LastPage")); location.href = "https://www.xmoj.tech/loginpage.php"; } let CurrentUsername = document.querySelector("#profile").innerText; @@ -1184,6 +1187,7 @@ async function main() { } if (UtilityEnabled("AutoLogin") && document.querySelector("#profile") != null && document.querySelector("#profile").innerHTML == "登录" && location.pathname != "/login.php" && location.pathname != "/loginpage.php" && location.pathname != "/lostpassword.php") { + if (logined) location.href = (localStorage.getItem("UserScript-LastPage") == null ? "/" : localStorage.getItem("UserScript-LastPage")); localStorage.setItem("UserScript-LastPage", location.pathname + location.search); location.href = "https://www.xmoj.tech/loginpage.php"; } From 02881c8534fa1a83c2ce05c397ced6dca4466fa9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Apr 2026 06:35:21 +0000 Subject: [PATCH 28/43] 3.4.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 244106ae3..c433e40dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.4.3", + "version": "3.4.4", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From d825aee3da8facce093397d7652ecd3e365548bb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Apr 2026 06:35:27 +0000 Subject: [PATCH 29/43] Update version info to 3.4.4 --- Update.json | 11 +++++++++++ XMOJ.user.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Update.json b/Update.json index d28c065e9..5b591f0be 100644 --- a/Update.json +++ b/Update.json @@ -3552,6 +3552,17 @@ } ], "Notes": "No release notes were provided for this release." + }, + "3.4.4": { + "UpdateDate": 1775975721817, + "Prerelease": true, + "UpdateContents": [ + { + "PR": 973, + "Description": "Fix loginpage.php Loop" + } + ], + "Notes": "Fix loginpage.php loop." } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index daba8d877..49f4d5631 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.4.3 +// @version 3.4.4 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen From 95bdcd78a0cb93132c4b08cd84e699c759eebeb1 Mon Sep 17 00:00:00 2001 From: zsTree Date: Sun, 12 Apr 2026 14:38:02 +0800 Subject: [PATCH 30/43] Refactor login check for clarity and efficiency Signed-off-by: zsTree --- XMOJ.user.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index 49f4d5631..1eb05d4a8 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -911,7 +911,8 @@ GM_registerMenuCommand("重置数据", () => { }); //otherwise CurrentUsername might be undefined -let logined = (document.querySelector('a').innerText == "Please logout First!"); +const firstAnchor = document.querySelector('a'); +const logined = !!firstAnchor && firstAnchor.innerText === 'Please logout First!'; if (UtilityEnabled("AutoLogin") && document.querySelector("body > a:nth-child(1)") != null && document.querySelector("body > a:nth-child(1)").innerText == "请登录后继续操作") { if (logined) location.href = (localStorage.getItem("UserScript-LastPage") == null ? "/" : localStorage.getItem("UserScript-LastPage")); localStorage.setItem("UserScript-LastPage", location.pathname + location.search); From 20abaf0b35bc9544e3256aa2223b181bf854903e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Apr 2026 06:38:26 +0000 Subject: [PATCH 31/43] Update time and description of 3.4.4 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 5b591f0be..0cd8346ee 100644 --- a/Update.json +++ b/Update.json @@ -3554,7 +3554,7 @@ "Notes": "No release notes were provided for this release." }, "3.4.4": { - "UpdateDate": 1775975721817, + "UpdateDate": 1775975900964, "Prerelease": true, "UpdateContents": [ { From 1fdc33cb0415f637692f82503320ff1f3b2e97c9 Mon Sep 17 00:00:00 2001 From: boomzero Date: Sun, 12 Apr 2026 19:30:51 +0800 Subject: [PATCH 32/43] Revert /v1 endpoint migration while keeping version metadata Reverts the API route changes from #969 that added /v1/ prefixes to all backend endpoints, while preserving the 3.4.3 version bump. Co-Authored-By: Claude Opus 4.6 --- XMOJ.user.js | 12 ++++++------ messages.html | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index eecedc5c6..15b76f721 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -505,7 +505,7 @@ let RequestAPI = (Action, Data, CallBack) => { } GM_xmlhttpRequest({ method: "POST", - url: (UtilityEnabled("SuperDebug") ? "http://127.0.0.1:8787/v1/" : "https://api.xmoj-bbs.me/v1/") + Action, + url: (UtilityEnabled("SuperDebug") ? "http://127.0.0.1:8787/" : "https://api.xmoj-bbs.me/") + Action, headers: { "Content-Type": "application/json", "Cache-Control": "no-cache", @@ -643,7 +643,7 @@ function ConnectNotificationSocket() { return; } - let wsUrl = (UtilityEnabled("SuperDebug") ? "ws://127.0.0.1:8787" : "wss://api.xmoj-bbs.me") + "/v1/ws/notifications?SessionID=" + Session; + let wsUrl = (UtilityEnabled("SuperDebug") ? "ws://127.0.0.1:8787" : "wss://api.xmoj-bbs.me") + "/ws/notifications?SessionID=" + Session; if (UtilityEnabled("DebugMode")) { console.log("WebSocket: Connecting to", wsUrl); @@ -5021,7 +5021,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - Content.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + Content.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; Content.dispatchEvent(new Event("input")); } else { Content.value = Before + `![上传失败!` + ResponseData.Message + `]()` + After; @@ -5277,7 +5277,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentElement.dispatchEvent(new Event("input")); } else { ContentElement.value = Before + `![上传失败!]()` + After; @@ -5450,7 +5450,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentElement.dispatchEvent(new Event("input")); } else { ContentElement.value = Before + `![上传失败!]()` + After; @@ -5708,7 +5708,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentEditor.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentEditor.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentEditor.dispatchEvent(new Event("input")); } else { ContentEditor.value = Before + `![上传失败!]()` + After; diff --git a/messages.html b/messages.html index 794b2d3f0..ea7e2484a 100644 --- a/messages.html +++ b/messages.html @@ -367,8 +367,8 @@ 'use strict'; // ── Constants ────────────────────────────────────────────────────────────── -const API_BASE = 'https://api.xmoj-bbs.me/v1/'; -const ASSET_BASE = 'https://assets.xmoj-bbs.me/v1/GetImage?ImageID='; +const API_BASE = 'https://api.xmoj-bbs.me/'; +const ASSET_BASE = 'https://assets.xmoj-bbs.me/GetImage?ImageID='; const XMOJ_BASE = 'https://www.xmoj.tech'; const WEBUI_VERSION = 'webui-1.0.0'; const STORAGE_USER = 'xmoj-msg-username'; From 11180a8a619f69526a014ab00c1b5bfe6dea10c9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Apr 2026 11:31:44 +0000 Subject: [PATCH 33/43] 3.4.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 244106ae3..c433e40dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.4.3", + "version": "3.4.4", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From 57467ea763c15a5bb9dd5cdaea71f08bf1c64578 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Apr 2026 11:31:49 +0000 Subject: [PATCH 34/43] Update version info to 3.4.4 --- Update.json | 11 +++++++++++ XMOJ.user.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Update.json b/Update.json index d28c065e9..6b9bbafdb 100644 --- a/Update.json +++ b/Update.json @@ -3552,6 +3552,17 @@ } ], "Notes": "No release notes were provided for this release." + }, + "3.4.4": { + "UpdateDate": 1775993504358, + "Prerelease": true, + "UpdateContents": [ + { + "PR": 975, + "Description": "Revert /v1 endpoint migration" + } + ], + "Notes": "Revert the `/v1` endpoint migration from #969 to restore original API routes." } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index 15b76f721..370e74d6d 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.4.3 +// @version 3.4.4 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen From 522d37fa0e44d0a7ab97b162d03427a5122121e1 Mon Sep 17 00:00:00 2001 From: zsTree Date: Sun, 12 Apr 2026 23:49:53 +0800 Subject: [PATCH 35/43] Fix loginpage.php Loop Signed-off-by: zsTree --- XMOJ.user.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/XMOJ.user.js b/XMOJ.user.js index 1eb05d4a8..57d597482 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.4.4 +// @version 3.4.5 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen @@ -505,7 +505,7 @@ let RequestAPI = (Action, Data, CallBack) => { } GM_xmlhttpRequest({ method: "POST", - url: (UtilityEnabled("SuperDebug") ? "http://127.0.0.1:8787/v1/" : "https://api.xmoj-bbs.me/v1/") + Action, + url: (UtilityEnabled("SuperDebug") ? "http://127.0.0.1:8787/" : "https://api.xmoj-bbs.me/") + Action, headers: { "Content-Type": "application/json", "Cache-Control": "no-cache", @@ -643,7 +643,7 @@ function ConnectNotificationSocket() { return; } - let wsUrl = (UtilityEnabled("SuperDebug") ? "ws://127.0.0.1:8787" : "wss://api.xmoj-bbs.me") + "/v1/ws/notifications?SessionID=" + Session; + let wsUrl = (UtilityEnabled("SuperDebug") ? "ws://127.0.0.1:8787" : "wss://api.xmoj-bbs.me") + "/ws/notifications?SessionID=" + Session; if (UtilityEnabled("DebugMode")) { console.log("WebSocket: Connecting to", wsUrl); @@ -911,18 +911,19 @@ GM_registerMenuCommand("重置数据", () => { }); //otherwise CurrentUsername might be undefined -const firstAnchor = document.querySelector('a'); -const logined = !!firstAnchor && firstAnchor.innerText === 'Please logout First!'; +let loginStatus; +await fetch("https://www.xmoj.tech/loginpage.php") + .then((response) => response.text()) + .then((data) => (loginStatus = data)); +const logined = loginStatus == "Please logout First!"; if (UtilityEnabled("AutoLogin") && document.querySelector("body > a:nth-child(1)") != null && document.querySelector("body > a:nth-child(1)").innerText == "请登录后继续操作") { - if (logined) location.href = (localStorage.getItem("UserScript-LastPage") == null ? "/" : localStorage.getItem("UserScript-LastPage")); localStorage.setItem("UserScript-LastPage", location.pathname + location.search); location.href = "https://www.xmoj.tech/loginpage.php"; } let SearchParams = new URLSearchParams(location.search); let ServerURL = (UtilityEnabled("DebugMode") ? "https://ghpages.xmoj-bbs.me/" : "https://www.xmoj-bbs.me") -if (document.querySelector("#profile") === null) { - if (logined) location.href = (localStorage.getItem("UserScript-LastPage") == null ? "/" : localStorage.getItem("UserScript-LastPage")); +if (document.querySelector("#profile") === null && !logined) { location.href = "https://www.xmoj.tech/loginpage.php"; } let CurrentUsername = document.querySelector("#profile").innerText; @@ -1187,8 +1188,7 @@ async function main() { document.querySelector("body > div > div.jumbotron").className = "mt-3"; } - if (UtilityEnabled("AutoLogin") && document.querySelector("#profile") != null && document.querySelector("#profile").innerHTML == "登录" && location.pathname != "/login.php" && location.pathname != "/loginpage.php" && location.pathname != "/lostpassword.php") { - if (logined) location.href = (localStorage.getItem("UserScript-LastPage") == null ? "/" : localStorage.getItem("UserScript-LastPage")); + if (UtilityEnabled("AutoLogin") && document.querySelector("#profile") != null && document.querySelector("#profile").innerHTML == "登录" && location.pathname != "/login.php" && location.pathname != "/loginpage.php" && location.pathname != "/lostpassword.php" && !logined) { localStorage.setItem("UserScript-LastPage", location.pathname + location.search); location.href = "https://www.xmoj.tech/loginpage.php"; } @@ -5026,7 +5026,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - Content.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + Content.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; Content.dispatchEvent(new Event("input")); } else { Content.value = Before + `![上传失败!` + ResponseData.Message + `]()` + After; @@ -5282,7 +5282,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentElement.dispatchEvent(new Event("input")); } else { ContentElement.value = Before + `![上传失败!]()` + After; @@ -5455,7 +5455,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentElement.dispatchEvent(new Event("input")); } else { ContentElement.value = Before + `![上传失败!]()` + After; @@ -5713,7 +5713,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentEditor.value = Before + `![](https://assets.xmoj-bbs.me/v1/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentEditor.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentEditor.dispatchEvent(new Event("input")); } else { ContentEditor.value = Before + `![上传失败!]()` + After; From 2415c7f9b8d6fac56535d3397f314b9631075866 Mon Sep 17 00:00:00 2001 From: zsTree Date: Sun, 12 Apr 2026 23:50:21 +0800 Subject: [PATCH 36/43] Bump version from 3.4.4 to 3.4.5 Signed-off-by: zsTree --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c433e40dc..e2238633e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.4.4", + "version": "3.4.5", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From b5397c66192d365df09e68981606429171a15946 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Apr 2026 15:52:34 +0000 Subject: [PATCH 37/43] Update time and description of 3.4.5 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index d1b3061f7..4248829dc 100644 --- a/Update.json +++ b/Update.json @@ -3565,7 +3565,7 @@ "Notes": "Revert the `/v1` endpoint migration from #969 to restore original API routes." }, "3.4.5": { - "UpdateDate": 1775975900964, + "UpdateDate": 1776009148847, "Prerelease": true, "UpdateContents": [ { From e23fdd65fab82ee4488e5541d515e5b0106bd3ce Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 Apr 2026 15:57:19 +0000 Subject: [PATCH 38/43] Update time and description of 3.4.5 --- Update.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Update.json b/Update.json index 4248829dc..03af95500 100644 --- a/Update.json +++ b/Update.json @@ -3565,7 +3565,7 @@ "Notes": "Revert the `/v1` endpoint migration from #969 to restore original API routes." }, "3.4.5": { - "UpdateDate": 1776009148847, + "UpdateDate": 1776009434318, "Prerelease": true, "UpdateContents": [ { From e410e24cb728e44ab5a4cad901f76f09b88850d8 Mon Sep 17 00:00:00 2001 From: pythonSmall-Q Date: Fri, 24 Apr 2026 20:36:38 +0800 Subject: [PATCH 39/43] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=9A=90=E7=A7=81?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E3=80=81=E5=84=BF=E7=AB=A5=E4=BF=9D=E6=8A=A4?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E5=92=8C=E6=9C=8D=E5=8A=A1=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=EF=BC=8C=E5=B9=B6=E6=9B=B4=E6=96=B0=E9=A6=96?= =?UTF-8?q?=E9=A1=B5=E5=A4=87=E6=A1=88=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot --- child-protection.html | 36 ++++++++++++++++++++++++++++++++++++ index.html | 11 ++++++++++- privacy.html | 36 ++++++++++++++++++++++++++++++++++++ terms.html | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 child-protection.html create mode 100644 privacy.html create mode 100644 terms.html diff --git a/child-protection.html b/child-protection.html new file mode 100644 index 000000000..f22784403 --- /dev/null +++ b/child-protection.html @@ -0,0 +1,36 @@ + + + + + + 儿童保护协议 - 小明的OJ增强脚本 + + + + +
+

儿童保护协议

+

生效日期:2026-04-24

+ +

一、适用范围

+

本协议适用于未满十四周岁儿童相关信息处理活动,以及监护人对儿童使用服务的管理与监督。

+ +

二、监护人责任

+

监护人应指导并监督儿童合理使用网络服务,避免泄露隐私信息,防止沉迷与不当互动。

+ +

三、儿童信息保护

+

我们坚持最小必要原则处理信息,不会在无正当理由情况下收集与服务无关的儿童个人信息。

+ +

四、风险防护措施

+

我们将持续优化内容展示、交互提醒和异常行为识别机制,降低儿童接触不适宜内容和网络风险的可能性。

+ +

五、监护人权利

+

监护人有权查阅、更正或删除儿童相关信息,并可通过反馈渠道提出限制处理、停止服务等申请。

+ +

六、联系我们

+

如您对儿童信息保护有疑问,请通过项目公开反馈渠道联系我们,我们会及时处理并反馈结果。

+ +

返回首页

+
+ + diff --git a/index.html b/index.html index 522de611a..f62c8fe7b 100644 --- a/index.html +++ b/index.html @@ -968,7 +968,16 @@

+
+
我们的网站在萌国备案啦!我们的备案号是:萌ICP备20240425号
+ +
-
我们的网站在萌国备案啦!我们的备案号是:萌ICP备20240425号
diff --git a/privacy.html b/privacy.html new file mode 100644 index 000000000..3f4aa5f9a --- /dev/null +++ b/privacy.html @@ -0,0 +1,36 @@ + + + + + + 隐私协议 - 小明的OJ增强脚本 + + + + +
+

隐私协议

+

生效日期:2026-04-24

+ +

一、我们收集的信息

+

为提供基础功能,我们可能会处理您在使用脚本时主动提供的数据,包括账号标识、消息内容、页面偏好设置、日志与故障排查信息。

+ +

二、信息使用目的

+

我们仅在实现脚本功能、改进产品体验、保障服务安全与处理用户反馈的必要范围内使用信息,不会将您的信息用于与服务无关的用途。

+ +

三、信息存储与保护

+

我们采取合理的技术与管理措施保护数据安全,尽量减少未授权访问、披露、篡改或丢失风险。数据仅在达到处理目的所需期限内保存。

+ +

四、信息共享与披露

+

除法律法规另有要求,或经您明确同意外,我们不会向无关第三方出售、出租或共享您的个人信息。

+ +

五、您的权利

+

您有权访问、更正、删除相关信息,也可以通过项目反馈渠道申请注销相关服务能力。我们会在合理期限内处理您的请求。

+ +

六、协议更新

+

本协议可能根据功能调整而更新。更新后将通过官网页面公示,继续使用服务即视为您已阅读并同意更新内容。

+ +

返回首页

+
+ + diff --git a/terms.html b/terms.html new file mode 100644 index 000000000..12b520400 --- /dev/null +++ b/terms.html @@ -0,0 +1,36 @@ + + + + + + 服务协议 - 小明的OJ增强脚本 + + + + +
+

服务协议

+

生效日期:2026-04-24

+ +

一、协议说明

+

本协议用于规范您使用小明的OJ增强脚本及相关网页服务的行为。您访问或使用服务即表示同意本协议条款。

+ +

二、服务内容

+

服务包含用户脚本功能、页面增强能力以及相关支持页面。我们会在不降低整体安全性的前提下持续迭代功能。

+ +

三、用户义务

+

您应遵守适用法律法规,不得利用服务从事违法违规活动,不得干扰平台正常运行或侵犯他人合法权益。

+ +

四、知识产权

+

本项目代码及文档受开源协议及相关法律保护。您在使用、修改或分发时需遵守对应许可证条款。

+ +

五、免责与限制

+

在法律允许范围内,服务按“现状”提供。因网络、第三方平台变更、不可抗力或用户自身操作导致的损失,我们不承担超出法律要求的责任。

+ +

六、协议变更与终止

+

我们有权根据业务调整更新协议。若您不同意更新内容,可停止使用服务。您违反本协议时,我们可采取限制措施。

+ +

返回首页

+
+ + From 9abf256c4a40dadfebff4cd842256b65fc9ecfc7 Mon Sep 17 00:00:00 2001 From: pythonSmall-Q Date: Fri, 24 Apr 2026 20:54:05 +0800 Subject: [PATCH 40/43] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E4=B8=AD=E5=BF=83=E7=99=BB=E5=BD=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E5=B9=B6=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=92=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot --- index.html | 3 ++ messages.html | 114 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index f62c8fe7b..831cf4716 100644 --- a/index.html +++ b/index.html @@ -55,6 +55,9 @@ + diff --git a/messages.html b/messages.html index ea7e2484a..06b43e2eb 100644 --- a/messages.html +++ b/messages.html @@ -73,6 +73,9 @@

登录

+ @@ -216,6 +219,22 @@
第二步:在 XMOJ 上点击书签
+ + + @@ -377,6 +396,11 @@ const SCROLL_THRESHOLD = 80; const MAX_IMAGE_BYTES = 5 * 1024 * 1024; const PREVIEW_LEN = 60; +const OAUTH_AUTHORIZE_URL = 'https://sso.xmoj-bbs.me/authorize'; +const OAUTH_CLIENT_ID = 'app_0f4cbbddfa42c0c4576cba8f7598d0a2'; +const OAUTH_SCOPE = 'openid profile email xmoj_profile'; +const OAUTH_REDIRECT_URI = 'https://xmoj-bbs.me/messages.html'; +const STORAGE_OAUTH_STATE = 'xmoj-msg-oauth-state'; // ── State ────────────────────────────────────────────────────────────────── let currentUser = null; // { username, phpsessid } @@ -931,6 +955,7 @@ }); document.getElementById('tab-bookmarklet').style.display = tab === 'bookmarklet' ? '' : 'none'; document.getElementById('tab-manual').style.display = tab === 'manual' ? '' : 'none'; + document.getElementById('tab-sso').style.display = tab === 'sso' ? '' : 'none'; } document.querySelectorAll('#loginTabs .nav-link').forEach(function(btn) { @@ -939,6 +964,89 @@ }); }); +function generateUuidV4() { + if (window.crypto && window.crypto.randomUUID) return window.crypto.randomUUID(); + if (window.crypto && window.crypto.getRandomValues) { + var bytes = new Uint8Array(16); + window.crypto.getRandomValues(bytes); + bytes[6] = (bytes[6] & 0x0f) | 0x40; + bytes[8] = (bytes[8] & 0x3f) | 0x80; + var hex = Array.from(bytes).map(function(b) { return b.toString(16).padStart(2, '0'); }).join(''); + return [hex.slice(0, 8), hex.slice(8, 12), hex.slice(12, 16), hex.slice(16, 20), hex.slice(20)].join('-'); + } + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0; + var v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); +} + +function startSsoLogin() { + var state = generateUuidV4() + '.' + generateUuidV4(); + localStorage.setItem(STORAGE_OAUTH_STATE, state); + var params = new URLSearchParams({ + response_type: 'code', + client_id: OAUTH_CLIENT_ID, + redirect_uri: OAUTH_REDIRECT_URI, + scope: OAUTH_SCOPE, + state: state + }); + location.href = OAUTH_AUTHORIZE_URL + '?' + params.toString(); +} + +async function exchangeSsoCode(code, state) { + var res = await fetch(API_BASE + 'ExchangeSSOCode', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + Code: code, + State: state, + RedirectURI: OAUTH_REDIRECT_URI, + ClientID: OAUTH_CLIENT_ID + }) + }); + if (!res.ok) throw new Error('HTTP ' + res.status); + return res.json(); +} + +async function handleSsoCallback() { + var url = new URL(location.href); + var code = url.searchParams.get('code'); + var state = url.searchParams.get('state'); + if (!code) return false; + + var expectedState = localStorage.getItem(STORAGE_OAUTH_STATE); + if (!state || !expectedState || state !== expectedState) { + showToast('统一认证登录失败:state 校验失败', 'danger'); + url.searchParams.delete('code'); + url.searchParams.delete('state'); + history.replaceState(null, '', url.pathname + (url.searchParams.toString() ? '?' + url.searchParams.toString() : '')); + return false; + } + + try { + var result = await exchangeSsoCode(code, state); + if (!result || !result.Success || !result.Data) { + throw new Error((result && result.Message) || '后端未返回有效登录数据'); + } + if (!result.Data.Username || !result.Data.SessionID) { + throw new Error('返回数据缺少 Username 或 SessionID'); + } + + localStorage.removeItem(STORAGE_OAUTH_STATE); + saveSession(result.Data.Username, result.Data.SessionID); + url.searchParams.delete('code'); + url.searchParams.delete('state'); + history.replaceState(null, '', url.pathname + (url.searchParams.toString() ? '?' + url.searchParams.toString() : '')); + showToast('统一认证登录成功', 'success'); + onLoggedIn(); + return true; + } catch (err) { + showToast('统一认证登录失败:' + err.message, 'danger'); + return false; + } +} + // ── Event Wiring ─────────────────────────────────────────────────────────── document.getElementById('btn-manual-login').addEventListener('click', function() { var username = document.getElementById('input-username').value.trim(); @@ -948,6 +1056,8 @@ onLoggedIn(); }); +document.getElementById('btn-sso-login').addEventListener('click', startSsoLogin); + document.getElementById('btn-logout').addEventListener('click', logout); document.getElementById('btn-refresh-list').addEventListener('click', loadMailList); @@ -1034,7 +1144,7 @@ }); // ── Boot ─────────────────────────────────────────────────────────────────── -(function init() { +(async function init() { initTheme(); initBookmarklet(); @@ -1050,6 +1160,8 @@ return; } + if (await handleSsoCallback()) return; + if (loadSession()) { onLoggedIn(); } else { From f6b0dcc97f4dc9963357fba5f913228fa1038a7c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 18:18:07 +0800 Subject: [PATCH 41/43] Switch all backend endpoints to api.xmoj-script.uk (#980) * switch endpoint to api.xmoj-script.uk for everything Agent-Logs-Url: https://github.com/XMOJ-Script-dev/XMOJ-Script/sessions/3a87c529-2f63-4617-8be5-5b9f3c33f751 Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com> * Update ASSET_BASE URL to use assets subdomain Signed-off-by: Shan Wenxiao * 3.4.6 * Update version info to 3.4.6 * Update image upload URLs to new asset location Signed-off-by: Shan Wenxiao * Update time and description of 3.4.6 * Update ServerURL for script debugging Signed-off-by: Shan Wenxiao * Update time and description of 3.4.6 * Update SSO button for development version Signed-off-by: Shan Wenxiao * Update time and description of 3.4.6 * Remove badge from messages link in navigation Signed-off-by: Shan Wenxiao * Update time and description of 3.4.6 --------- Signed-off-by: Shan Wenxiao Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com> Co-authored-by: Shan Wenxiao Co-authored-by: github-actions[bot] --- Update.json | 11 +++++++++++ XMOJ.user.js | 21 +++++++++++---------- index.html | 4 +--- messages.html | 7 +++---- package.json | 2 +- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/Update.json b/Update.json index 03af95500..e5371722f 100644 --- a/Update.json +++ b/Update.json @@ -3574,6 +3574,17 @@ } ], "Notes": "Fix loginpage.php loop." + }, + "3.4.6": { + "UpdateDate": 1777708421566, + "Prerelease": true, + "UpdateContents": [ + { + "PR": 980, + "Description": "Switch all backend endpoints to api.xmoj-script.uk" + } + ], + "Notes": "No release notes were provided for this release." } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index 57d597482..e9d5874f8 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.4.5 +// @version 3.4.6 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen @@ -21,10 +21,11 @@ // @grant GM_setValue // @grant GM_getValue // @grant GM_cookie -// @homepage https://www.xmoj-bbs.me/ -// @supportURL https://support.xmoj-bbs.me/form/8050213e-c806-4680-b414-0d1c48263677 +// @homepage https://www.xmoj-script.uk/ +// @supportURL https://github.com/XMOJ-Script-dev/XMOJ-Script/issues // @connect api.xmoj-bbs.tech // @connect api.xmoj-bbs.me +// @connect api.xmoj-script.uk // @connect challenges.cloudflare.com // @connect cppinsights.io // @connect cdnjs.cloudflare.com @@ -505,7 +506,7 @@ let RequestAPI = (Action, Data, CallBack) => { } GM_xmlhttpRequest({ method: "POST", - url: (UtilityEnabled("SuperDebug") ? "http://127.0.0.1:8787/" : "https://api.xmoj-bbs.me/") + Action, + url: (UtilityEnabled("SuperDebug") ? "http://127.0.0.1:8787/" : "https://api.xmoj-script.uk/") + Action, headers: { "Content-Type": "application/json", "Cache-Control": "no-cache", @@ -643,7 +644,7 @@ function ConnectNotificationSocket() { return; } - let wsUrl = (UtilityEnabled("SuperDebug") ? "ws://127.0.0.1:8787" : "wss://api.xmoj-bbs.me") + "/ws/notifications?SessionID=" + Session; + let wsUrl = (UtilityEnabled("SuperDebug") ? "ws://127.0.0.1:8787" : "wss://api.xmoj-script.uk") + "/ws/notifications?SessionID=" + Session; if (UtilityEnabled("DebugMode")) { console.log("WebSocket: Connecting to", wsUrl); @@ -922,7 +923,7 @@ if (UtilityEnabled("AutoLogin") && document.querySelector("body > a:nth-child(1) } let SearchParams = new URLSearchParams(location.search); -let ServerURL = (UtilityEnabled("DebugMode") ? "https://ghpages.xmoj-bbs.me/" : "https://www.xmoj-bbs.me") +let ServerURL = (UtilityEnabled("DebugMode") ? "https://ghpages.xmoj-script.uk/" : "https://www.xmoj-script.uk") if (document.querySelector("#profile") === null && !logined) { location.href = "https://www.xmoj.tech/loginpage.php"; } @@ -5026,7 +5027,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - Content.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + Content.value = Before + `![](https://assets.xmoj-script.uk/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; Content.dispatchEvent(new Event("input")); } else { Content.value = Before + `![上传失败!` + ResponseData.Message + `]()` + After; @@ -5282,7 +5283,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentElement.value = Before + `![](https://assets.xmoj-script.uk/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentElement.dispatchEvent(new Event("input")); } else { ContentElement.value = Before + `![上传失败!]()` + After; @@ -5455,7 +5456,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentElement.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentElement.value = Before + `![](https://assets.xmoj-script.uk/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentElement.dispatchEvent(new Event("input")); } else { ContentElement.value = Before + `![上传失败!]()` + After; @@ -5713,7 +5714,7 @@ int main() "Image": Reader.result }, (ResponseData) => { if (ResponseData.Success) { - ContentEditor.value = Before + `![](https://assets.xmoj-bbs.me/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; + ContentEditor.value = Before + `![](https://assets.xmoj-script.uk/GetImage?ImageID=${ResponseData.Data.ImageID})` + After; ContentEditor.dispatchEvent(new Event("input")); } else { ContentEditor.value = Before + `![上传失败!]()` + After; diff --git a/index.html b/index.html index 831cf4716..fda3f2058 100644 --- a/index.html +++ b/index.html @@ -48,9 +48,7 @@ 关于 @@ -386,8 +386,8 @@ 'use strict'; // ── Constants ────────────────────────────────────────────────────────────── -const API_BASE = 'https://api.xmoj-bbs.me/'; -const ASSET_BASE = 'https://assets.xmoj-bbs.me/GetImage?ImageID='; +const API_BASE = 'https://api.xmoj-script.uk/'; +const ASSET_BASE = 'https://assets.xmoj-script.uk/GetImage?ImageID='; const XMOJ_BASE = 'https://www.xmoj.tech'; const WEBUI_VERSION = 'webui-1.0.0'; const STORAGE_USER = 'xmoj-msg-username'; @@ -991,7 +991,6 @@ scope: OAUTH_SCOPE, state: state }); - location.href = OAUTH_AUTHORIZE_URL + '?' + params.toString(); } async function exchangeSsoCode(code, state) { diff --git a/package.json b/package.json index e2238633e..a2e6b7367 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.4.5", + "version": "3.4.6", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From 672f046114f22429dd24c5198e046d7024ef3e9f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 16 May 2026 11:25:58 +0000 Subject: [PATCH 42/43] 3.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a2e6b7367..3cb8e34a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmoj-script", - "version": "3.4.6", + "version": "3.5.0", "description": "an improvement script for xmoj.tech", "main": "AddonScript.js", "scripts": { From 38376df38e98aa8f8858441688e899ef01459c7b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 16 May 2026 11:25:59 +0000 Subject: [PATCH 43/43] Update to release 3.5.0 --- Update.json | 31 +++++++++++++++++++++++++++++++ XMOJ.user.js | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Update.json b/Update.json index e5371722f..3d3ee4cb7 100644 --- a/Update.json +++ b/Update.json @@ -3585,6 +3585,37 @@ } ], "Notes": "No release notes were provided for this release." + }, + "3.5.0": { + "UpdateDate": 1778930758179, + "Prerelease": false, + "UpdateContents": [ + { + "PR": 961, + "Description": "feat: Cross-device settings sync via cloud backend" + }, + { + "PR": 963, + "Description": "feat: Add hourly periodic cloud settings sync" + }, + { + "PR": 969, + "Description": "Migrate XMOJ-BBS client endpoints to /v1 routes" + }, + { + "PR": 975, + "Description": "Revert /v1 endpoint migration" + }, + { + "PR": 973, + "Description": "Fix loginpage.php Loop" + }, + { + "PR": 980, + "Description": "Switch all backend endpoints to api.xmoj-script.uk" + } + ], + "Notes": "No release notes were provided for this release." } } } \ No newline at end of file diff --git a/XMOJ.user.js b/XMOJ.user.js index e9d5874f8..f4c9e6bf3 100644 --- a/XMOJ.user.js +++ b/XMOJ.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name XMOJ -// @version 3.4.6 +// @version 3.5.0 // @description XMOJ增强脚本 // @author @XMOJ-Script-dev, @langningchen and the community // @namespace https://github/langningchen