Skip to content

Commit

Permalink
feat(luogu-problem-export): init
Browse files Browse the repository at this point in the history
  • Loading branch information
Molmin committed Feb 5, 2024
1 parent 878fd45 commit 4b23dff
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 4 deletions.
5 changes: 5 additions & 0 deletions luogu-problem-export/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
package-lock.json
config.json
*.js
data
42 changes: 42 additions & 0 deletions luogu-problem-export/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { readFileSync, writeFileSync } from 'node:fs'
import { ensureDirSync } from 'fs-extra'
import LuoguAccountService from './service'
import yamljs from 'yamljs'

const config = JSON.parse(readFileSync('config.json').toString())

const luogu = new LuoguAccountService(
config.uid,
`_uid=${config.uid}; __client_id=${config.client_id}`,
)

async function main() {
if (!await luogu.isLoggedIn()) return console.error('Logged in failed')
console.log('Logged in')
for (const pid of config.pids) {
await new Promise((resolve) => setTimeout(resolve, 10000))
console.log(`Getting problem ${pid}`)
ensureDirSync(`data/${pid}/testdata`)
ensureDirSync(`data/${pid}/additional_file`)
const problem = await luogu.getProblem(pid)
writeFileSync(`data/${pid}/problem_zh.md`, problem.content)
writeFileSync(`data/${pid}/problem.yaml`, yamljs.stringify({
pid,
owner: 1,
title: problem.title,
tag: [],
nSubmit: 0,
nAccept: 0,
}))
const testdataZip = await luogu.getTestdata(pid)
testdataZip.extractAllTo(`data/${pid}/testdata/`, true)
const rids = await luogu.getRecords(pid)
for (const rid of rids) {
const record = await luogu.getRecord(rid)
if (!record) continue
writeFileSync(`data/${pid}/additional_file/${rid}-${record.score}.cpp`, record.code)
}
}
}

main()
25 changes: 25 additions & 0 deletions luogu-problem-export/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "luogu-problem-export",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"start": "tsc && node index.js"
},
"author": "Milmon <[email protected]>",
"license": "GPL-3.0",
"dependencies": {
"@types/node": "^20.11.16",
"adm-zip": "^0.5.10",
"fs-extra": "^11.2.0",
"superagent": "^8.1.2",
"yamljs": "^0.3.0"
},
"devDependencies": {
"@types/adm-zip": "^0.5.5",
"@types/fs-extra": "^11.0.4",
"@types/superagent": "^8.1.3",
"@types/yamljs": "^0.2.34",
"typescript": "^5.3.3"
}
}
82 changes: 82 additions & 0 deletions luogu-problem-export/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import superagent from 'superagent'
import AdmZip from 'adm-zip'

const UA = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
'AppleWebKit/537.36 (KHTML, like Gecko)',
'Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.76',
].join(' ')

export default class LuoguAccountService {
constructor(
private userId: number,
private cookie: string,
private endPoint = 'https://www.luogu.com.cn',
) { }

get(url: string) {
return superagent
.get(this.endPoint + url)
.set('Cookie', this.cookie)
.set('User-Agent', UA)
}
post(url: string) {
return superagent
.post(this.endPoint + url)
.set('Cookie', this.cookie)
.set('User-Agent', UA)
}

async isLoggedIn(): Promise<boolean> {
const { body } = await this.get('/problem/list').query({ _contentOnly: true })
return body.currentUser.uid === this.userId
}

async getProblem(pid: string) {
const { body: { currentData: { problem } } } = await this
.get(`/problem/${pid}`).query({ _contentOnly: true })
let content = ''
if (problem.background) content += `## 题目背景\n\n${problem.background}\n\n`
if (problem.description) content += `## 题目描述\n\n${problem.description}\n\n`
if (problem.inputFormat) content += `## 输入格式\n\n${problem.inputFormat}\n\n`
if (problem.outputFormat) content += `## 输出格式\n\n${problem.outputFormat}\n\n`
let id = 0
for (const [input, output] of problem.samples) {
id++
content += `\`\`\`input${id}\n${input}\n\`\`\`\n\n`
content += `\`\`\`output${id}\n${output}\n\`\`\`\n\n`
}
if (problem.hint) content += `## 提示\n\n${problem.hint}\n\n`
return {
title: problem.title,
content: content.trim(),
// limits:
}
}

async getTestdata(pid: string) {
const { body } = await this.get(`/fe/api/problem/generateDataDownloadLink/${pid}`)
return new AdmZip(body)
}

async getRecords(pid: string) {
let rids: number[] = []
for (let page = 1; ; page++) {
const { body: { currentData: { records: { result: records } } } } = await this
.get('/record/list').query({ pid, page, _contentOnly: true })
const ids = records.map((record: any) => record.id)
if (ids.length === 0) return rids
rids = rids.concat(ids)
}
}

async getRecord(rid: number) {
const { body: { currentData } } = await this
.get(`/record/${rid}`).query({ _contentOnly: true })
if (currentData.errorMessage) return null
else return {
code: currentData.record.sourceCode,
score: currentData.record.score || 0,
}
}
}
10 changes: 10 additions & 0 deletions luogu-problem-export/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
5 changes: 1 addition & 4 deletions xmoj-crawl/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,5 @@
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
"ts-node": {
"esm": true
}
}
}

0 comments on commit 4b23dff

Please sign in to comment.