diff --git a/lua/cp/submit.lua b/lua/cp/submit.lua
index 50d884f..77e3d66 100644
--- a/lua/cp/submit.lua
+++ b/lua/cp/submit.lua
@@ -54,7 +54,6 @@ function M.submit(opts)
logger.log('Source file not found', { level = vim.log.levels.ERROR })
return
end
- source_file = vim.fn.fnamemodify(source_file, ':p')
prompt_credentials(platform, function(creds)
vim.cmd.update()
diff --git a/scrapers/kattis.py b/scrapers/kattis.py
index 734705e..43ce1f3 100644
--- a/scrapers/kattis.py
+++ b/scrapers/kattis.py
@@ -221,17 +221,25 @@ async def _save_kattis_cookies(client: httpx.AsyncClient) -> None:
_COOKIE_PATH.write_text(json.dumps(cookies))
+async def _check_kattis_login(client: httpx.AsyncClient) -> bool:
+ try:
+ r = await client.get(BASE_URL + "/", headers=HEADERS, timeout=HTTP_TIMEOUT)
+ text = r.text.lower()
+ return "sign out" in text or "logout" in text or "my profile" in text
+ except Exception:
+ return False
+
+
async def _do_kattis_login(
client: httpx.AsyncClient, username: str, password: str
) -> bool:
- client.cookies.clear()
r = await client.post(
- f"{BASE_URL}/login",
+ f"{BASE_URL}/login/email",
data={"user": username, "password": password, "script": "true"},
headers=HEADERS,
timeout=HTTP_TIMEOUT,
)
- return r.status_code == 200
+ return r.status_code == 200 and "login failed" not in r.text.lower()
class KattisScraper(BaseScraper):
@@ -322,7 +330,9 @@ class KattisScraper(BaseScraper):
async with httpx.AsyncClient(follow_redirects=True) as client:
await _load_kattis_cookies(client)
- if not client.cookies:
+ print(json.dumps({"status": "checking_login"}), flush=True)
+ logged_in = bool(client.cookies) and await _check_kattis_login(client)
+ if not logged_in:
print(json.dumps({"status": "logging_in"}), flush=True)
ok = await _do_kattis_login(client, username, password)
if not ok:
@@ -341,35 +351,18 @@ class KattisScraper(BaseScraper):
}
if contest_id != problem_id:
data["contest"] = contest_id
-
- async def _do_submit() -> httpx.Response:
- return await client.post(
+ try:
+ r = await client.post(
f"{BASE_URL}/submit",
data=data,
files={"sub_file[]": (f"solution.{ext}", source, "text/plain")},
headers=HEADERS,
timeout=HTTP_TIMEOUT,
)
-
- try:
- r = await _do_submit()
r.raise_for_status()
except Exception as e:
return self._submit_error(f"Submit request failed: {e}")
- if r.text == "Request validation failed":
- _COOKIE_PATH.unlink(missing_ok=True)
- print(json.dumps({"status": "logging_in"}), flush=True)
- ok = await _do_kattis_login(client, username, password)
- if not ok:
- return self._submit_error("Login failed (bad credentials?)")
- await _save_kattis_cookies(client)
- try:
- r = await _do_submit()
- r.raise_for_status()
- except Exception as e:
- return self._submit_error(f"Submit request failed: {e}")
-
sid_m = re.search(r"Submission ID:\s*(\d+)", r.text, re.IGNORECASE)
sid = sid_m.group(1) if sid_m else ""
return SubmitResult(
@@ -383,10 +376,21 @@ class KattisScraper(BaseScraper):
return self._login_error("Missing username or password")
async with httpx.AsyncClient(follow_redirects=True) as client:
+ await _load_kattis_cookies(client)
+ if client.cookies:
+ print(json.dumps({"status": "checking_login"}), flush=True)
+ if await _check_kattis_login(client):
+ return LoginResult(
+ success=True,
+ error="",
+ credentials={"username": username, "password": password},
+ )
+
print(json.dumps({"status": "logging_in"}), flush=True)
ok = await _do_kattis_login(client, username, password)
if not ok:
return self._login_error("Login failed (bad credentials?)")
+
await _save_kattis_cookies(client)
return LoginResult(
success=True,
diff --git a/scrapers/language_ids.py b/scrapers/language_ids.py
index 1abfcc6..6870aa3 100644
--- a/scrapers/language_ids.py
+++ b/scrapers/language_ids.py
@@ -16,7 +16,7 @@ LANGUAGE_IDS = {
"python": "python",
},
"kattis": {
- "cpp": "C++",
+ "cpp": "C++17",
"python": "Python 3",
},
"codechef": {
diff --git a/scrapers/usaco.py b/scrapers/usaco.py
index 074cbf9..73ec6b1 100644
--- a/scrapers/usaco.py
+++ b/scrapers/usaco.py
@@ -29,7 +29,7 @@ CONNECTIONS = 4
_COOKIE_PATH = Path.home() / ".cache" / "cp-nvim" / "usaco-cookies.json"
_LOGIN_PATH = "/current/tpcm/login-session.php"
-_SUBMIT_PATH = "/current/tpcm/submit-solution.php"
+_SUBMIT_PATH = "/current/tpcm/submitproblem.php"
_LANG_KEYWORDS: dict[str, list[str]] = {
"cpp": ["c++17", "c++ 17", "g++17", "c++", "cpp"],
@@ -141,16 +141,13 @@ def _parse_problem_page(html: str) -> dict[str, Any]:
def _pick_lang_option(select_body: str, language_id: str) -> str | None:
keywords = _LANG_KEYWORDS.get(language_id.lower(), [language_id.lower()])
- options = [
- (m.group(1), m.group(2).strip().lower())
- for m in re.finditer(
- r'