Codeforces API 的简单应用:使用桌面通知系统显示特定比赛最近一次提交记录
Redshift_Shine · · 科技·工程
效果展示
背景
AtCoder Beginner Contest 里面总有那么几道签到题。有时候为了追求更快的速度,还没等上一题的评测结果出来我就得开始写下一题。于是就会让我在写下一题的时候经常担心上一题的代码有没有寄掉。
于是我产生了一个想法:利用桌面通知系统,直接把比赛中最近一次提交的结果以通知的形式显示在屏幕上,这样就省去了再次打开提交界面的麻烦。
然后我发现了一个巨大的问题。AtCoder 没有 API!!!我显然是知道破掉 Cloudflare 的方法的(网上有一堆关于这个的库),但是因为 AtCoder 没有 API,所以为了这个功能我还要手动处理账号登录这些事情,非常麻烦。然后突然想到 Codeforces 有 API,所以先拿 Codeforces API 做一个简单一点的版本。
代码
完整代码如下:
import requests, time, os, random, sys, datetime, hashlib
prev_id = 0
key = ''
private_key = ''
handle = ''
contestId = sys.argv[1]
while True:
try:
cdt = time.mktime(datetime.datetime.now().timetuple())
pattern = f'contest.status?apiKey={key}&contestId={contestId}&count=1&from=1&handle={handle}&time={int(cdt)}'
rdn = str(random.randint(0,999999)).zfill(6)
pattern = 'https://codeforces.com/api/' + pattern + f'&apiSig={rdn}{hashlib.sha512((rdn + '/' + pattern + '#' + private_key).encode()).hexdigest()}'
# print(pattern)
response = requests.get(pattern)
# print(response.json())
if response.json()['status'] != 'OK':
time.sleep(5)
continue
body = response.json()['result'][0]
if prev_id == body['id'] or not 'verdict' in body or body['verdict'] == 'TESTING':
time.sleep(5)
continue
os.system(f'notify-send --urgency={'normal' if body['verdict'] == 'OK' else 'critical'} {body['verdict']} \
\"{body['author']['contestId']}{body['problem']['index']} {body['problem']['name']}\\n\
Passed testcases: {body['passedTestCount']}\\n\
Time consumed: {body['timeConsumedMillis']}ms\"')
prev_id = body['id']
except:
pass
time.sleep(5)
你需要自行填入 Codeforces API 的公钥私钥以及你的用户名。
上述代码使用了 Linux 系统中的 notify-send 指令。网上有该命令的 Windows 移植版本,若在 Windows 上使用需要预先下载移植版本并添加至 path 中。Windows 的显示效果可能与 Linux 有所不同,而 Linux 上使用的不同桌面环境/窗口管理器的显示效果根据配置也会有所不同。该文章开头的效果在 Arch Linux Hyprland + mako 实现,配置文件由 cascade 提供。
使用方法
该脚本需要一个参数,即该比赛的编号。不是 round 号,而是访问对应网页时在地址栏显示的编号。
调用例:
$ python script.py 2124
随后保持该脚本运行即可。该脚本在正常运行情况下不会在终端输出任何内容。