Skip to content

sync: dev to extern-contrib - #1022

Open
github-actions[bot] wants to merge 18 commits into
extern-contribfrom
dev
Open

github-actions[bot] wants to merge 18 commits into
extern-contribfrom
dev

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

sync-branches: New code has just landed in dev, so let's bring extern-contrib up to speed!

Summary by Sourcery

Synchronize the external-contrib branch with dev by improving captcha recovery and making ended-contest fallback submissions reliable.

New Features:

  • Automatically refresh unreadable captcha images up to five times when auto-solving is enabled.

Bug Fixes:

  • Improve submissions for ended contests by retrying cooldown responses, reporting server errors, and refreshing the captcha after captcha failures.
  • Prevent stale captcha answers from being entered while a replacement image is loading.

Enhancements:

  • Centralize ended-contest fallback submission handling and user-facing submission status reporting.

Build:

  • Bump the userscript and package versions to 3.7.0.

Chores:

  • Update release metadata in Update.json for the synchronized versions.

Summary by cubic

Syncs extern-contrib with dev, delivering the 3.6.5 fallback-submission fix and the 3.6.6 captcha auto-refresh as release 3.7.0. XMOJ.user.js and package.json are bumped to 3.7.0, and Update.json marks 3.6.5 and 3.6.6 as prereleases with 3.7.0 as the release.

Bug Fixes

  • Fallback submissions after a contest ends wait out 请勿重复提交 cooldowns (3 seconds apart, up to 5 attempts) instead of being silently dropped.
  • Other fallback failures surface the server's .jumbotron message, and captcha errors refresh the captcha and stop retrying.
  • The captcha input is locked while a new image loads so stale answers aren't sent.

New Features

  • When the auto-captcha solver can't read an image, the script automatically fetches a new one (up to 5 times).

Written for commit fce1af6. Summary will update on new commits.

Review in cubic

boomzero and others added 8 commits September 19, 2026 08:23
回退路径本身可以解析出真实题号,问题在 POST 之后:内层 fetch 只把响应
console.log 掉,从不判断成功与否,随后外层无条件覆盖成"提交失败"。日志里
那次回退实际收到的是 XMOJ 的提交冷却页(`请勿重复提交`,HUSTOJ 的
$OJ_SUBMIT_COOLDOWN_TIME 默认 5 秒,XMOJ 渲染成页面而非 302),响应被丢掉,
所以状态里没有任何提交记录。

- 把回退逻辑抽成 SubmitToEndedContestProblem,返回 {Success, Message}
- 只把 redirected 当成功信号,成功后 return,不再被外层覆盖
- 遇到 `请勿重复提交` 等冷却过去后重试(3 秒一次,最多 5 次)
- 其余失败从响应的 .jumbotron 取服务端原文,不再显示通用报错
- 遇到 `验证码错误` 立即刷新验证码并停止重试(答案已被消耗)
- 题号改用 /\d+/ 提取,原 substring(2, 6) 会把 5 位题号截成 4 位
- 补齐缺失的 GetCaptchaParameter(),并在解析失败时恢复提交按钮

Closes #1017

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
冷却等待期间验证码输入框和刷新按钮仍可交互。如果用户在这 3 秒里清空了
输入框或刷新了图片,下一次重试会用空的 GetCaptchaParameter() 发出请求,
而空答案会让服务端把本 session 的 4 位验证码换成 8 位。

在循环每次 POST 之前调用 CaptchaIsMissing()(它自己会提示并恢复按钮),
并用 Handled 标志让外层直接返回,不覆盖它设置的提示。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
contest.php 或 submit.php 的 fetch 被 reject(网络错误)时,异常会一路穿出
SubmitToEndedContestProblem、穿出 .then 回调、穿出 PassCheck 的 async 监听器
——整条链上没有任何 catch。结果 ShowSubmitStatus 和恢复按钮的两行都不会执行,
提交按钮永远停在"正在提交...",而错误框在监听器开头已经被设成 display: none,
用户什么提示都看不到。这正是本 PR 声称要修掉的那个症状。

把两处网络请求都包进 try/catch,失败时返回错误信息交给外层显示。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ack-1017

fix: 比赛结束后回退提交不再被静默丢弃
@sourcery-ai

sourcery-ai Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Version 3.6.5 improves submission of problems from ended contests by extracting the fallback into a resilient, retrying workflow, centralizing status/error handling, and updating release metadata.

Sequence diagram for ended-contest problem submission

sequenceDiagram
    actor User
    participant SubmitHandler
    participant XMOJ as XMOJ
    participant ContestPage
    participant SubmitPage

    User->>SubmitHandler: click PassCheck
    SubmitHandler->>XMOJ: POST submit.php
    XMOJ-->>SubmitHandler: 没有这个比赛!
    SubmitHandler->>ContestPage: fetch contest.php?cid=ContestID
    ContestPage-->>SubmitHandler: contest HTML
    SubmitHandler->>SubmitHandler: parse RealPID
    loop up to 5 attempts
        SubmitHandler->>SubmitHandler: CaptchaIsMissing()
        SubmitHandler->>SubmitPage: POST submit.php with RealPID
        alt redirected
            SubmitPage-->>SubmitHandler: redirect response
            SubmitHandler->>XMOJ: navigate to result URL
        else 请勿重复提交
            SubmitPage-->>SubmitHandler: cooldown response
            SubmitHandler->>SubmitHandler: wait 3 seconds
        else submission result
            SubmitPage-->>SubmitHandler: result HTML
        end
    end
    SubmitHandler->>SubmitHandler: ShowSubmitStatus(Message)
Loading

Flow diagram for resilient ended-contest submission fallback

flowchart TD
    A[Initial submission fails with 没有这个比赛] --> B[Fetch contest.php using cid]
    B --> C{Contest page valid?}
    C -- No --> D[Show failure status]
    C -- Yes --> E[Parse contest problem list and resolve RealPID]
    E --> F{RealPID found?}
    F -- No --> D
    F -- Yes --> G[Check captcha]
    G --> H[POST submission to submit.php for RealPID]
    H --> I{Response}
    I -- Redirected --> J[Navigate to submission result]
    I -- 验证码错误 --> K[RefreshCaptcha and show captcha error]
    I -- 请勿重复提交 --> L{Attempts remain?}
    L -- Yes --> M[Wait 3 seconds and retry]
    M --> G
    L -- No --> D
    I -- Other failure --> D
Loading

File-Level Changes

Change Details Files
Extract and harden ended-contest submission into a reusable fallback workflow.
  • Fetch and parse the contest page to map contest positions to real problem IDs, including variable-length IDs.
  • Handle contest-page, parsing, network, captcha, and server errors with user-visible messages.
  • Retry rate-limited submissions with a three-second cooldown and re-check the captcha before each attempt.
  • Preserve redirect-based success handling and report submission progress through a shared status helper.
XMOJ.user.js
Refactor normal submission failure handling to use the new fallback and shared status display.
  • Invoke the ended-contest fallback when submit.php reports that the contest no longer exists.
  • Restore submit controls consistently for fallback failures and cancellation paths.
  • Centralize error-message rendering and editor cleanup.
XMOJ.user.js
Bump the script/package release version and add update metadata.
  • Update the userscript and npm package versions from 3.6.4 to 3.6.5.
  • Add the new update metadata entry.
XMOJ.user.js
package.json
Update.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 19, 2026

Copy link
Copy Markdown

Deploying xmoj-script-dev-channel with  Cloudflare Pages  Cloudflare Pages

Latest commit: fce1af6
Status: ✅  Deploy successful!
Preview URL: https://ce2b43f8.xmoj-script-dev-channel.pages.dev

View logs

@sourcery-ai sourcery-ai Bot left a comment

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.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="XMOJ.user.js" line_range="4639" />
<code_context>
-                                        SmartAlert("XMOJ-Script internal error!\n\n" + e + "\n\n" + "If you see this message, please report it to the developer.\nDon't forget to include console logs and a way to reproduce the error!\n\nDon't want to see this message? Disable DebugMode.");
+                                let FailMessage = "提交失败!请关闭脚本后重试!";
+                                if (text.indexOf("没有这个比赛!") !== -1 && SearchParams.get("pid") !== null) {
+                                    const FallbackResult = await SubmitToEndedContestProblem(CodeMirrorElement.getValue(), o2Switch, ShowSubmitStatus);
+                                    if (FallbackResult.Success || FallbackResult.Handled) {
+                                        return;
</code_context>
<issue_to_address>
**issue (bug_risk):** The fetch that submits the original contest request is still outside any try/catch. When this submit.php request rejects because of a network failure, the PassCheck async listener rejects before it can restore the submit button or show an error, so the button remains stuck on “正在提交...” with no visible message.

**Triggers:** When the initial contest submission request fails at the network level before returning a Response.

**Suggested fix:** Wrap the PassCheck submit fetch and response-processing chain in try/catch, and restore `Submit.disabled`/`Submit.value` while displaying a network-error message in the catch path.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and when the contest-to-problem mapping or retry logic is wrong, this code can POST the user's source to the wrong problem or create duplicate submissions, and those external submission records are not undone by reverting the script. The impact is bounded to the affected submissions and does not involve money or access control.

Blocking findings: XMOJ.user.js:4639


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread XMOJ.user.js
SmartAlert("XMOJ-Script internal error!\n\n" + e + "\n\n" + "If you see this message, please report it to the developer.\nDon't forget to include console logs and a way to reproduce the error!\n\nDon't want to see this message? Disable DebugMode.");
let FailMessage = "提交失败!请关闭脚本后重试!";
if (text.indexOf("没有这个比赛!") !== -1 && SearchParams.get("pid") !== null) {
const FallbackResult = await SubmitToEndedContestProblem(CodeMirrorElement.getValue(), o2Switch, ShowSubmitStatus);

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.

issue (bug_risk): The fetch that submits the original contest request is still outside any try/catch. When this submit.php request rejects because of a network failure, the PassCheck async listener rejects before it can restore the submit button or show an error, so the button remains stuck on “正在提交...” with no visible message.

Triggers: When the initial contest submission request fails at the network level before returning a Response.

Suggested fix: Wrap the PassCheck submit fetch and response-processing chain in try/catch, and restore Submit.disabled/Submit.value while displaying a network-error message in the catch path.

@hendragon-bot hendragon-bot Bot added the user-script This issue or pull request is related to the main user script label Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L user-script This issue or pull request is related to the main user script

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant