fix: expand language IDs, fix AtCoder submit, normalize logging (#353)
## Problem Language version coverage was incomplete across all platforms, AtCoder submit used a stale cookie fast-path that caused silent failures, and raw `vim.notify` calls throughout the codebase produced inconsistent or missing `[cp.nvim]:` prefixes. ## Solution Remove cookie persistence from AtCoder login/submit (always fresh login), increase the submit nav timeout to 40s, and switch to in-memory buffer upload with the correct per-language extension from a full `_LANGUAGE_ID_EXTENSION` map covering all 116 AtCoder languages. Expand `LANGUAGE_VERSIONS` in `constants.lua` with all AtCoder languages, 15 new CF languages with full version variants, and 50+ Kattis languages. Fix AtCoder `prolog` ID (`6079`→`6081`, was Pony) and remove the non-existent `racket` entry. Replace all raw `vim.notify` calls with `logger.log`. Simplify the submit language doc to point at `constants.lua` rather than maintaining a static table.
This commit is contained in:
parent
1ac521a126
commit
291de4e137
13 changed files with 356 additions and 114 deletions
|
|
@ -1054,20 +1054,14 @@ Set {version} globally or per-platform:
|
|||
},
|
||||
},
|
||||
<
|
||||
Available versions per platform ~
|
||||
Available versions ~
|
||||
|
||||
Platform cpp python java rust
|
||||
AtCoder c++20/23 python3, pypy3 java rust
|
||||
Codeforces c++17/20/23 python3, pypy3 - -
|
||||
CSES c++11/17/20 python3, pypy3 java rust2018/2021
|
||||
Kattis c++17/20/23 python3 java rust
|
||||
USACO c++11/17 python3 java -
|
||||
CodeChef c++20 python3, pypy3 java rust
|
||||
Each platform supports all of its own languages and compiler versions.
|
||||
The full list of version keys is in `lua/cp/constants.lua` under
|
||||
`LANGUAGE_VERSIONS`. Use any key from that table as the {version} value.
|
||||
|
||||
Using a raw platform ID ~
|
||||
|
||||
If your preferred version is not listed, you can bypass version
|
||||
lookup by setting {submit_id} to the raw platform language ID:
|
||||
To bypass version lookup entirely, set {submit_id} to the raw platform
|
||||
language ID (the value from the platform's submit page dropdown):
|
||||
>lua
|
||||
platforms = {
|
||||
codeforces = {
|
||||
|
|
@ -1075,9 +1069,6 @@ lookup by setting {submit_id} to the raw platform language ID:
|
|||
},
|
||||
},
|
||||
<
|
||||
To find the raw ID, open the platform's submit page in your browser,
|
||||
inspect the language dropdown, and copy the <option value="..."> for
|
||||
your desired language.
|
||||
|
||||
==============================================================================
|
||||
OPEN *cp-open*
|
||||
|
|
|
|||
|
|
@ -262,15 +262,8 @@ local function validate_language(id, lang)
|
|||
|
||||
if lang.commands.build ~= nil then
|
||||
vim.validate({ build = { lang.commands.build, { 'table' } } })
|
||||
if not has_tokens(lang.commands.build, { '{source}', '{binary}' }) then
|
||||
error(('[cp.nvim] languages.%s.commands.build must include {source} and {binary}'):format(id))
|
||||
end
|
||||
for _, k in ipairs({ 'run', 'debug' }) do
|
||||
if lang.commands[k] then
|
||||
if not has_tokens(lang.commands[k], { '{binary}' }) then
|
||||
error(('[cp.nvim] languages.%s.commands.%s must include {binary}'):format(id, k))
|
||||
end
|
||||
end
|
||||
if not has_tokens(lang.commands.build, { '{source}' }) then
|
||||
error(('[cp.nvim] languages.%s.commands.build must include {source}'):format(id))
|
||||
end
|
||||
else
|
||||
for _, k in ipairs({ 'run', 'debug' }) do
|
||||
|
|
|
|||
|
|
@ -75,14 +75,67 @@ M.signal_codes = {
|
|||
|
||||
M.LANGUAGE_VERSIONS = {
|
||||
atcoder = {
|
||||
cpp = { ['c++20'] = '6054', ['c++23'] = '6017' },
|
||||
python = { python3 = '6082', pypy3 = '6083' },
|
||||
cpp = { ['c++20'] = '6054', ['c++23'] = '6017', ['c++23-clang'] = '6116' },
|
||||
python = { python3 = '6082', pypy3 = '6083', codon = '6115' },
|
||||
java = { java = '6056' },
|
||||
rust = { rust = '6088' },
|
||||
c = { c23clang = '6013', c23gcc = '6014' },
|
||||
go = { go = '6051', gccgo = '6050' },
|
||||
haskell = { haskell = '6052' },
|
||||
csharp = { csharp = '6015', ['csharp-aot'] = '6016' },
|
||||
kotlin = { kotlin = '6062' },
|
||||
ruby = { ruby = '6087', truffleruby = '6086' },
|
||||
javascript = { bun = '6057', deno = '6058', nodejs = '6059' },
|
||||
typescript = { deno = '6100', bun = '6101', nodejs = '6102' },
|
||||
scala = { scala = '6090', ['scala-native'] = '6091' },
|
||||
ocaml = { ocaml = '6073' },
|
||||
dart = { dart = '6033' },
|
||||
elixir = { elixir = '6038' },
|
||||
erlang = { erlang = '6041' },
|
||||
fsharp = { fsharp = '6042' },
|
||||
swift = { swift = '6095' },
|
||||
zig = { zig = '6111' },
|
||||
nim = { nim = '6072', ['nim-old'] = '6071' },
|
||||
lua = { lua = '6067', luajit = '6068' },
|
||||
perl = { perl = '6076' },
|
||||
php = { php = '6077' },
|
||||
pascal = { pascal = '6075' },
|
||||
crystal = { crystal = '6028' },
|
||||
d = { dmd = '6030', gdc = '6031', ldc = '6032' },
|
||||
julia = { julia = '6114' },
|
||||
r = { r = '6084' },
|
||||
commonlisp = { commonlisp = '6027' },
|
||||
scheme = { chezscheme = '6092', gauche = '6093' },
|
||||
clojure = { clojure = '6022', ['clojure-aot'] = '6023', babashka = '6021' },
|
||||
ada = { ada = '6002' },
|
||||
bash = { bash = '6008' },
|
||||
fortran = { fortran2023 = '6047', fortran2018 = '6046', fortran77 = '6048' },
|
||||
gleam = { gleam = '6049' },
|
||||
lean = { lean = '6065' },
|
||||
pony = { pony = '6079' },
|
||||
prolog = { prolog = '6081' },
|
||||
vala = { vala = '6106' },
|
||||
v = { v = '6105' },
|
||||
sql = { duckdb = '6118' },
|
||||
},
|
||||
codeforces = {
|
||||
cpp = { ['c++17'] = '54', ['c++20'] = '89', ['c++23'] = '91' },
|
||||
python = { python3 = '31', pypy3 = '70' },
|
||||
cpp = { ['c++17'] = '54', ['c++20'] = '89', ['c++23'] = '91', c11 = '43' },
|
||||
python = { python3 = '31', pypy3 = '70', python2 = '7', pypy2 = '40', ['pypy3-old'] = '41' },
|
||||
java = { java8 = '36', java21 = '87' },
|
||||
kotlin = { ['1.7'] = '83', ['1.9'] = '88', ['2.2'] = '99' },
|
||||
rust = { ['2021'] = '75', ['2024'] = '98' },
|
||||
go = { go = '32' },
|
||||
csharp = { mono = '9', dotnet3 = '65', dotnet6 = '79', dotnet9 = '96' },
|
||||
haskell = { haskell = '12' },
|
||||
javascript = { v8 = '34', nodejs = '55' },
|
||||
ruby = { ruby = '67' },
|
||||
scala = { scala = '20' },
|
||||
ocaml = { ocaml = '19' },
|
||||
d = { d = '28' },
|
||||
perl = { perl = '13' },
|
||||
php = { php = '6' },
|
||||
pascal = { freepascal = '4', pascalabc = '51' },
|
||||
fsharp = { fsharp = '97' },
|
||||
},
|
||||
cses = {
|
||||
cpp = { ['c++17'] = 'C++17' },
|
||||
|
|
@ -92,9 +145,58 @@ M.LANGUAGE_VERSIONS = {
|
|||
},
|
||||
kattis = {
|
||||
cpp = { ['c++17'] = 'C++', ['c++20'] = 'C++', ['c++23'] = 'C++' },
|
||||
python = { python3 = 'Python 3' },
|
||||
python = { python3 = 'Python 3', python2 = 'Python 2' },
|
||||
java = { java = 'Java' },
|
||||
rust = { rust = 'Rust' },
|
||||
ada = { ada = 'Ada' },
|
||||
algol60 = { algol60 = 'Algol 60' },
|
||||
algol68 = { algol68 = 'Algol 68' },
|
||||
apl = { apl = 'APL' },
|
||||
bash = { bash = 'Bash' },
|
||||
bcpl = { bcpl = 'BCPL' },
|
||||
bqn = { bqn = 'BQN' },
|
||||
c = { c = 'C' },
|
||||
cobol = { cobol = 'COBOL' },
|
||||
commonlisp = { commonlisp = 'Common Lisp' },
|
||||
crystal = { crystal = 'Crystal' },
|
||||
csharp = { csharp = 'C#' },
|
||||
d = { d = 'D' },
|
||||
dart = { dart = 'Dart' },
|
||||
elixir = { elixir = 'Elixir' },
|
||||
erlang = { erlang = 'Erlang' },
|
||||
forth = { forth = 'Forth' },
|
||||
fortran = { fortran = 'Fortran' },
|
||||
fortran77 = { fortran77 = 'Fortran 77' },
|
||||
fsharp = { fsharp = 'F#' },
|
||||
gerbil = { gerbil = 'Gerbil' },
|
||||
go = { go = 'Go' },
|
||||
haskell = { haskell = 'Haskell' },
|
||||
icon = { icon = 'Icon' },
|
||||
javascript = { javascript = 'JavaScript (Node.js)', spidermonkey = 'JavaScript (SpiderMonkey)' },
|
||||
julia = { julia = 'Julia' },
|
||||
kotlin = { kotlin = 'Kotlin' },
|
||||
lua = { lua = 'Lua' },
|
||||
modula2 = { modula2 = 'Modula-2' },
|
||||
nim = { nim = 'Nim' },
|
||||
objectivec = { objectivec = 'Objective-C' },
|
||||
ocaml = { ocaml = 'OCaml' },
|
||||
octave = { octave = 'Octave' },
|
||||
odin = { odin = 'Odin' },
|
||||
pascal = { pascal = 'Pascal' },
|
||||
perl = { perl = 'Perl' },
|
||||
php = { php = 'PHP' },
|
||||
pli = { pli = 'PL/I' },
|
||||
prolog = { prolog = 'Prolog' },
|
||||
racket = { racket = 'Racket' },
|
||||
ruby = { ruby = 'Ruby' },
|
||||
scala = { scala = 'Scala' },
|
||||
simula = { simula = 'Simula 67' },
|
||||
smalltalk = { smalltalk = 'Smalltalk' },
|
||||
snobol = { snobol = 'SNOBOL' },
|
||||
swift = { swift = 'Swift' },
|
||||
typescript = { typescript = 'TypeScript' },
|
||||
visualbasic = { visualbasic = 'Visual Basic' },
|
||||
zig = { zig = 'Zig' },
|
||||
},
|
||||
usaco = {
|
||||
cpp = { ['c++11'] = 'cpp', ['c++17'] = 'cpp' },
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ local function ensure_initialized()
|
|||
local ok, result = pcall(config_module.setup, user_config)
|
||||
if not ok then
|
||||
local msg = tostring(result):gsub('^.+:%d+: ', '')
|
||||
vim.notify(msg, vim.log.levels.ERROR)
|
||||
logger.log(msg, { level = vim.log.levels.ERROR, override = true, sync = true })
|
||||
return false
|
||||
end
|
||||
config_module.set_current_config(result)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
local logger = require('cp.log')
|
||||
local picker_utils = require('cp.pickers')
|
||||
|
||||
local M = {}
|
||||
|
|
@ -9,9 +10,9 @@ local function contest_picker(platform, refresh, language)
|
|||
local contests = picker_utils.get_platform_contests(platform, refresh)
|
||||
|
||||
if vim.tbl_isempty(contests) then
|
||||
vim.notify(
|
||||
logger.log(
|
||||
("No contests found for platform '%s'"):format(platform_display_name),
|
||||
vim.log.levels.WARN
|
||||
{ level = vim.log.levels.WARN }
|
||||
)
|
||||
return
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ local conf = require('telescope.config').values
|
|||
local action_state = require('telescope.actions.state')
|
||||
local actions = require('telescope.actions')
|
||||
|
||||
local logger = require('cp.log')
|
||||
local picker_utils = require('cp.pickers')
|
||||
|
||||
local M = {}
|
||||
|
|
@ -14,9 +15,9 @@ local function contest_picker(opts, platform, refresh, language)
|
|||
local contests = picker_utils.get_platform_contests(platform, refresh)
|
||||
|
||||
if vim.tbl_isempty(contests) then
|
||||
vim.notify(
|
||||
logger.log(
|
||||
('No contests found for platform: %s'):format(platform_display_name),
|
||||
vim.log.levels.WARN
|
||||
{ level = vim.log.levels.WARN }
|
||||
)
|
||||
return
|
||||
end
|
||||
|
|
|
|||
|
|
@ -239,13 +239,13 @@ function M.start(platform, contest_id, language)
|
|||
logger.log('Contest started!', { level = vim.log.levels.INFO, override = true })
|
||||
race_try_setup(p, c, l, 1, token)
|
||||
elseif should_notify(r) then
|
||||
vim.notify(
|
||||
('[cp.nvim]: %s race "%s" starts in %s'):format(
|
||||
logger.log(
|
||||
('%s race "%s" starts in %s'):format(
|
||||
constants.PLATFORM_DISPLAY_NAMES[race_state.platform] or race_state.platform,
|
||||
race_state.contest_name,
|
||||
format_countdown(r)
|
||||
),
|
||||
vim.log.levels.INFO
|
||||
{ level = vim.log.levels.INFO, override = true }
|
||||
)
|
||||
end
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ function M.submit(opts)
|
|||
|
||||
prompt_credentials(platform, function(creds)
|
||||
vim.cmd.update()
|
||||
vim.notify('[cp.nvim] Submitting...', vim.log.levels.INFO)
|
||||
logger.log('Submitting...', { level = vim.log.levels.INFO, override = true })
|
||||
|
||||
require('cp.scraper').submit(
|
||||
platform,
|
||||
|
|
@ -89,7 +89,10 @@ function M.submit(opts)
|
|||
creds,
|
||||
function(ev)
|
||||
vim.schedule(function()
|
||||
vim.notify('[cp.nvim] ' .. (STATUS_MSGS[ev.status] or ev.status), vim.log.levels.INFO)
|
||||
logger.log(
|
||||
STATUS_MSGS[ev.status] or ev.status,
|
||||
{ level = vim.log.levels.INFO, override = true }
|
||||
)
|
||||
end)
|
||||
end,
|
||||
function(result)
|
||||
|
|
|
|||
|
|
@ -142,7 +142,10 @@ local function discover_nix_submit_cmd()
|
|||
|
||||
local plugin_path = M.get_plugin_path()
|
||||
vim.cmd.redraw()
|
||||
vim.notify('Building submit environment...', vim.log.levels.INFO)
|
||||
logger.log(
|
||||
'Building submit environment...',
|
||||
{ level = vim.log.levels.INFO, override = true, sync = true }
|
||||
)
|
||||
vim.cmd.redraw()
|
||||
local result = vim
|
||||
.system(
|
||||
|
|
@ -209,7 +212,10 @@ local function discover_nix_python()
|
|||
end
|
||||
|
||||
local plugin_path = M.get_plugin_path()
|
||||
vim.notify('[cp.nvim] Building Python environment with nix...', vim.log.levels.INFO)
|
||||
logger.log(
|
||||
'Building Python environment with nix...',
|
||||
{ level = vim.log.levels.INFO, override = true, sync = true }
|
||||
)
|
||||
vim.cmd.redraw()
|
||||
local result = vim
|
||||
.system(
|
||||
|
|
@ -263,7 +269,10 @@ function M.setup_python_env()
|
|||
if not on_nixos and vim.fn.executable('uv') == 1 then
|
||||
local plugin_path = M.get_plugin_path()
|
||||
logger.log('Python env: uv sync (dir=' .. plugin_path .. ')')
|
||||
vim.notify('[cp.nvim] Setting up Python environment...', vim.log.levels.INFO)
|
||||
logger.log(
|
||||
'Setting up Python environment...',
|
||||
{ level = vim.log.levels.INFO, override = true, sync = true }
|
||||
)
|
||||
vim.cmd.redraw()
|
||||
|
||||
local env = vim.fn.environ()
|
||||
|
|
|
|||
|
|
@ -36,9 +36,96 @@ from .timeouts import (
|
|||
HTTP_TIMEOUT,
|
||||
)
|
||||
|
||||
_LANGUAGE_ID_EXTENSION = {
|
||||
_LANGUAGE_ID_EXTENSION: dict[str, str] = {
|
||||
"6002": "ada",
|
||||
"6003": "apl",
|
||||
"6004": "asm",
|
||||
"6005": "asm",
|
||||
"6006": "awk",
|
||||
"6008": "sh",
|
||||
"6009": "bas",
|
||||
"6010": "bc",
|
||||
"6012": "bf",
|
||||
"6013": "c",
|
||||
"6014": "c",
|
||||
"6015": "cs",
|
||||
"6016": "cs",
|
||||
"6017": "cc",
|
||||
"6021": "clj",
|
||||
"6022": "clj",
|
||||
"6023": "clj",
|
||||
"6025": "cljs",
|
||||
"6026": "cob",
|
||||
"6027": "lisp",
|
||||
"6028": "cr",
|
||||
"6030": "d",
|
||||
"6031": "d",
|
||||
"6032": "d",
|
||||
"6033": "dart",
|
||||
"6038": "ex",
|
||||
"6039": "el",
|
||||
"6041": "erl",
|
||||
"6042": "fs",
|
||||
"6043": "factor",
|
||||
"6044": "fish",
|
||||
"6045": "fth",
|
||||
"6046": "f90",
|
||||
"6047": "f90",
|
||||
"6048": "f",
|
||||
"6049": "gleam",
|
||||
"6050": "go",
|
||||
"6051": "go",
|
||||
"6052": "hs",
|
||||
"6053": "hx",
|
||||
"6054": "cc",
|
||||
"6056": "java",
|
||||
"6057": "js",
|
||||
"6058": "js",
|
||||
"6059": "js",
|
||||
"6060": "jule",
|
||||
"6061": "kk",
|
||||
"6062": "kt",
|
||||
"6065": "lean",
|
||||
"6066": "ll",
|
||||
"6067": "lua",
|
||||
"6068": "lua",
|
||||
"6071": "nim",
|
||||
"6072": "nim",
|
||||
"6073": "ml",
|
||||
"6074": "m",
|
||||
"6075": "pas",
|
||||
"6076": "pl",
|
||||
"6077": "php",
|
||||
"6079": "pony",
|
||||
"6080": "ps1",
|
||||
"6081": "pro",
|
||||
"6082": "py",
|
||||
"6083": "py",
|
||||
"6084": "r",
|
||||
"6085": "re",
|
||||
"6086": "rb",
|
||||
"6087": "rb",
|
||||
"6088": "rs",
|
||||
"6089": "py",
|
||||
"6090": "scala",
|
||||
"6091": "scala",
|
||||
"6092": "scm",
|
||||
"6093": "scm",
|
||||
"6094": "sd7",
|
||||
"6095": "swift",
|
||||
"6096": "tcl",
|
||||
"6100": "ts",
|
||||
"6101": "ts",
|
||||
"6102": "ts",
|
||||
"6105": "v",
|
||||
"6106": "vala",
|
||||
"6107": "v",
|
||||
"6109": "wat",
|
||||
"6111": "zig",
|
||||
"6114": "jl",
|
||||
"6115": "py",
|
||||
"6116": "cc",
|
||||
"6118": "sql",
|
||||
}
|
||||
|
||||
MIB_TO_MB = 1.048576
|
||||
|
|
@ -304,9 +391,6 @@ def _login_headless(credentials: dict[str, str]) -> LoginResult:
|
|||
|
||||
_ensure_browser()
|
||||
|
||||
cookie_cache = Path.home() / ".cache" / "cp-nvim" / "atcoder-cookies.json"
|
||||
cookie_cache.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
logged_in = False
|
||||
login_error: str | None = None
|
||||
|
||||
|
|
@ -352,13 +436,6 @@ def _login_headless(credentials: dict[str, str]) -> LoginResult:
|
|||
success=False, error="Login failed (bad credentials?)"
|
||||
)
|
||||
|
||||
try:
|
||||
browser_cookies = session.context.cookies()
|
||||
if any(c["name"] == "REVEL_SESSION" for c in browser_cookies):
|
||||
cookie_cache.write_text(json.dumps(browser_cookies))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return LoginResult(success=True, error="")
|
||||
except Exception as e:
|
||||
return LoginResult(success=False, error=str(e))
|
||||
|
|
@ -370,7 +447,6 @@ def _submit_headless(
|
|||
file_path: str,
|
||||
language_id: str,
|
||||
credentials: dict[str, str],
|
||||
_retried: bool = False,
|
||||
) -> "SubmitResult":
|
||||
try:
|
||||
from scrapling.fetchers import StealthySession # type: ignore[import-untyped,unresolved-import]
|
||||
|
|
@ -382,25 +458,8 @@ def _submit_headless(
|
|||
|
||||
_ensure_browser()
|
||||
|
||||
cookie_cache = Path.home() / ".cache" / "cp-nvim" / "atcoder-cookies.json"
|
||||
cookie_cache.parent.mkdir(parents=True, exist_ok=True)
|
||||
saved_cookies: list[dict[str, Any]] = []
|
||||
if cookie_cache.exists():
|
||||
try:
|
||||
saved_cookies = json.loads(cookie_cache.read_text())
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
logged_in = cookie_cache.exists() and not _retried
|
||||
login_error: str | None = None
|
||||
submit_error: str | None = None
|
||||
needs_relogin = False
|
||||
|
||||
def check_login(page):
|
||||
nonlocal logged_in
|
||||
logged_in = page.evaluate(
|
||||
"() => Array.from(document.querySelectorAll('a')).some(a => a.textContent.trim() === 'Sign Out')"
|
||||
)
|
||||
|
||||
def login_action(page):
|
||||
nonlocal login_error
|
||||
|
|
@ -416,9 +475,9 @@ def _submit_headless(
|
|||
login_error = str(e)
|
||||
|
||||
def submit_action(page):
|
||||
nonlocal submit_error, needs_relogin
|
||||
nonlocal submit_error
|
||||
if "/login" in page.url:
|
||||
needs_relogin = True
|
||||
submit_error = "Not logged in after login step"
|
||||
return
|
||||
try:
|
||||
_solve_turnstile(page)
|
||||
|
|
@ -430,9 +489,19 @@ def _submit_headless(
|
|||
f'select[name="data.LanguageId"] option[value="{language_id}"]'
|
||||
).wait_for(state="attached", timeout=BROWSER_ELEMENT_WAIT)
|
||||
page.select_option('select[name="data.LanguageId"]', language_id)
|
||||
page.set_input_files("#input-open-file", file_path)
|
||||
ext = _LANGUAGE_ID_EXTENSION.get(
|
||||
language_id, Path(file_path).suffix.lstrip(".") or "txt"
|
||||
)
|
||||
page.set_input_files(
|
||||
"#input-open-file",
|
||||
{
|
||||
"name": f"solution.{ext}",
|
||||
"mimeType": "text/plain",
|
||||
"buffer": Path(file_path).read_bytes(),
|
||||
},
|
||||
)
|
||||
page.wait_for_timeout(BROWSER_SETTLE_DELAY)
|
||||
page.locator('button[type="submit"]').click()
|
||||
page.locator('button[type="submit"]').click(no_wait_after=True)
|
||||
page.wait_for_url(
|
||||
lambda url: "/submissions/me" in url,
|
||||
timeout=BROWSER_SUBMIT_NAV_TIMEOUT["atcoder"],
|
||||
|
|
@ -445,15 +514,7 @@ def _submit_headless(
|
|||
headless=True,
|
||||
timeout=BROWSER_SESSION_TIMEOUT,
|
||||
google_search=False,
|
||||
cookies=saved_cookies if (cookie_cache.exists() and not _retried) else [],
|
||||
) as session:
|
||||
if not (cookie_cache.exists() and not _retried):
|
||||
print(json.dumps({"status": "checking_login"}), flush=True)
|
||||
session.fetch(
|
||||
f"{BASE_URL}/home", page_action=check_login, network_idle=True
|
||||
)
|
||||
|
||||
if not logged_in:
|
||||
print(json.dumps({"status": "logging_in"}), flush=True)
|
||||
session.fetch(
|
||||
f"{BASE_URL}/login",
|
||||
|
|
@ -461,9 +522,7 @@ def _submit_headless(
|
|||
solve_cloudflare=True,
|
||||
)
|
||||
if login_error:
|
||||
return SubmitResult(
|
||||
success=False, error=f"Login failed: {login_error}"
|
||||
)
|
||||
return SubmitResult(success=False, error=f"Login failed: {login_error}")
|
||||
|
||||
print(json.dumps({"status": "submitting"}), flush=True)
|
||||
session.fetch(
|
||||
|
|
@ -472,24 +531,6 @@ def _submit_headless(
|
|||
solve_cloudflare=True,
|
||||
)
|
||||
|
||||
try:
|
||||
browser_cookies = session.context.cookies()
|
||||
if any(c["name"] == "REVEL_SESSION" for c in browser_cookies):
|
||||
cookie_cache.write_text(json.dumps(browser_cookies))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if needs_relogin and not _retried:
|
||||
cookie_cache.unlink(missing_ok=True)
|
||||
return _submit_headless(
|
||||
contest_id,
|
||||
problem_id,
|
||||
file_path,
|
||||
language_id,
|
||||
credentials,
|
||||
_retried=True,
|
||||
)
|
||||
|
||||
if submit_error:
|
||||
return SubmitResult(success=False, error=submit_error)
|
||||
|
||||
|
|
|
|||
|
|
@ -338,13 +338,14 @@ class KattisScraper(BaseScraper):
|
|||
await _save_kattis_cookies(client)
|
||||
|
||||
print(json.dumps({"status": "submitting"}), flush=True)
|
||||
ext = "py" if "python" in language_id.lower() else "cpp"
|
||||
lang_lower = language_id.lower()
|
||||
mainclass = Path(file_path).stem if "java" in lang_lower else ""
|
||||
data: dict[str, str] = {
|
||||
"submit": "true",
|
||||
"script": "true",
|
||||
"language": language_id,
|
||||
"problem": problem_id,
|
||||
"mainclass": "",
|
||||
"mainclass": mainclass,
|
||||
"submit_ctr": "2",
|
||||
}
|
||||
if contest_id != problem_id:
|
||||
|
|
@ -354,7 +355,7 @@ class KattisScraper(BaseScraper):
|
|||
return await client.post(
|
||||
f"{BASE_URL}/submit",
|
||||
data=data,
|
||||
files={"sub_file[]": (f"solution.{ext}", source, "text/plain")},
|
||||
files={"sub_file[]": (Path(file_path).name, source, "text/plain")},
|
||||
headers=HEADERS,
|
||||
timeout=HTTP_TIMEOUT,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,10 +4,60 @@ LANGUAGE_IDS = {
|
|||
"python": "6082",
|
||||
"java": "6056",
|
||||
"rust": "6088",
|
||||
"c": "6014",
|
||||
"go": "6051",
|
||||
"haskell": "6052",
|
||||
"csharp": "6015",
|
||||
"kotlin": "6062",
|
||||
"ruby": "6087",
|
||||
"javascript": "6059",
|
||||
"typescript": "6100",
|
||||
"scala": "6090",
|
||||
"ocaml": "6073",
|
||||
"dart": "6033",
|
||||
"elixir": "6038",
|
||||
"erlang": "6041",
|
||||
"fsharp": "6042",
|
||||
"swift": "6095",
|
||||
"zig": "6111",
|
||||
"nim": "6072",
|
||||
"lua": "6067",
|
||||
"perl": "6076",
|
||||
"php": "6077",
|
||||
"pascal": "6075",
|
||||
"crystal": "6028",
|
||||
"d": "6030",
|
||||
"julia": "6114",
|
||||
"r": "6084",
|
||||
"commonlisp": "6027",
|
||||
"scheme": "6092",
|
||||
"clojure": "6022",
|
||||
"ada": "6002",
|
||||
"bash": "6008",
|
||||
"fortran": "6047",
|
||||
"gleam": "6049",
|
||||
"lean": "6065",
|
||||
"vala": "6106",
|
||||
"v": "6105",
|
||||
},
|
||||
"codeforces": {
|
||||
"cpp": "89",
|
||||
"python": "70",
|
||||
"java": "87",
|
||||
"kotlin": "99",
|
||||
"rust": "75",
|
||||
"go": "32",
|
||||
"csharp": "96",
|
||||
"haskell": "12",
|
||||
"javascript": "55",
|
||||
"ruby": "67",
|
||||
"scala": "20",
|
||||
"ocaml": "19",
|
||||
"d": "28",
|
||||
"perl": "13",
|
||||
"php": "6",
|
||||
"pascal": "4",
|
||||
"fsharp": "97",
|
||||
},
|
||||
"cses": {
|
||||
"cpp": "C++17",
|
||||
|
|
@ -25,6 +75,55 @@ LANGUAGE_IDS = {
|
|||
"python": "Python 3",
|
||||
"java": "Java",
|
||||
"rust": "Rust",
|
||||
"ada": "Ada",
|
||||
"algol60": "Algol 60",
|
||||
"algol68": "Algol 68",
|
||||
"apl": "APL",
|
||||
"bash": "Bash",
|
||||
"bcpl": "BCPL",
|
||||
"bqn": "BQN",
|
||||
"c": "C",
|
||||
"cobol": "COBOL",
|
||||
"commonlisp": "Common Lisp",
|
||||
"crystal": "Crystal",
|
||||
"csharp": "C#",
|
||||
"d": "D",
|
||||
"dart": "Dart",
|
||||
"elixir": "Elixir",
|
||||
"erlang": "Erlang",
|
||||
"forth": "Forth",
|
||||
"fortran": "Fortran",
|
||||
"fortran77": "Fortran 77",
|
||||
"fsharp": "F#",
|
||||
"gerbil": "Gerbil",
|
||||
"go": "Go",
|
||||
"haskell": "Haskell",
|
||||
"icon": "Icon",
|
||||
"javascript": "JavaScript (Node.js)",
|
||||
"julia": "Julia",
|
||||
"kotlin": "Kotlin",
|
||||
"lua": "Lua",
|
||||
"modula2": "Modula-2",
|
||||
"nim": "Nim",
|
||||
"objectivec": "Objective-C",
|
||||
"ocaml": "OCaml",
|
||||
"octave": "Octave",
|
||||
"odin": "Odin",
|
||||
"pascal": "Pascal",
|
||||
"perl": "Perl",
|
||||
"php": "PHP",
|
||||
"pli": "PL/I",
|
||||
"prolog": "Prolog",
|
||||
"racket": "Racket",
|
||||
"ruby": "Ruby",
|
||||
"scala": "Scala",
|
||||
"simula": "Simula 67",
|
||||
"smalltalk": "Smalltalk",
|
||||
"snobol": "SNOBOL",
|
||||
"swift": "Swift",
|
||||
"typescript": "TypeScript",
|
||||
"visualbasic": "Visual Basic",
|
||||
"zig": "Zig",
|
||||
},
|
||||
"codechef": {
|
||||
"cpp": "C++",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ BROWSER_NAV_TIMEOUT = 10000
|
|||
BROWSER_SUBMIT_NAV_TIMEOUT: defaultdict[str, int] = defaultdict(
|
||||
lambda: BROWSER_NAV_TIMEOUT
|
||||
)
|
||||
BROWSER_SUBMIT_NAV_TIMEOUT["atcoder"] = BROWSER_NAV_TIMEOUT * 2
|
||||
BROWSER_SUBMIT_NAV_TIMEOUT["codeforces"] = BROWSER_NAV_TIMEOUT * 2
|
||||
BROWSER_TURNSTILE_POLL = 5000
|
||||
BROWSER_ELEMENT_WAIT = 10000
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue