|
| 1 | +/** |
| 2 | + * Lyrio platform, which is used by [LibreOJ](https://loj.ac) under the hood. |
| 3 | + * @module |
| 4 | + */ |
| 5 | + |
| 6 | +import type { PlatformOptions } from '../platform'; |
| 7 | +import type { Problem as BaseProblem } from '../problem'; |
| 8 | +import { NotFoundError, Platform, UnexpectedResponseError } from '../platform'; |
| 9 | +import { UnOJError } from '../utils'; |
| 10 | + |
| 11 | +export type ProblemType = 'Traditional' | 'SubmitAnswer' | 'Interaction'; |
| 12 | + |
| 13 | +/** |
| 14 | + * Lyrio-specific problem type. |
| 15 | + * |
| 16 | + * Description is JSON-encoded Markdown. |
| 17 | + * |
| 18 | + * @example |
| 19 | + * ```ts |
| 20 | + * ({ |
| 21 | + * description: `[{"sectionTitle":"题目描述","type":"Text","text":"输入 $ a $ 和 $ b $,输出 $ a + b $ 的结果。"},{"sectionTitle":"输入格式","type":"Text","text":"一行两个正整数 $ a $ 和 $ b $。"},{"sectionTitle":"输出格式","type":"Text","text":"一行一个正整数 $ a + b $。"},{"sectionTitle":"样例","type":"Sample","sampleId":0,"text":"根据数学知识有 $ 1 + 2 = 3 $。"},{"sectionTitle":"数据范围","type":"Text","text":"对于 $ 100\\% $ 的数据,$ 1 \\leq a, b \\leq 10 ^ 6 $。"}]`, |
| 22 | + * difficulty: undefined, |
| 23 | + * id: '1', |
| 24 | + * link: 'https://loj.ac/p/1', |
| 25 | + * memoryLimit: 536870912, |
| 26 | + * samples: [{ |
| 27 | + * input: '1 2', |
| 28 | + * output: '3', |
| 29 | + * }], |
| 30 | + * tags: [{ |
| 31 | + * color: 'black', |
| 32 | + * id: 1, |
| 33 | + * name: '系统测试', |
| 34 | + * nameLocale: 'zh_CN', |
| 35 | + * }], |
| 36 | + * timeLimit: 2000, |
| 37 | + * title: 'A + B 问题', |
| 38 | + * type: 'Traditional', |
| 39 | + * }) |
| 40 | + * ``` |
| 41 | + */ |
| 42 | +export type Problem = BaseProblem< |
| 43 | + string, |
| 44 | + number, |
| 45 | + undefined, |
| 46 | + Array<{ id: number, name: string, color: string }>, |
| 47 | + ProblemType |
| 48 | +>; |
| 49 | + |
| 50 | +export const DEFAULT_BASE_URL = 'https://api.loj.ac'; |
| 51 | + |
| 52 | +/** |
| 53 | + * Lyrio platform. |
| 54 | + * |
| 55 | + * I18n is supported. |
| 56 | + */ |
| 57 | +export default class Lyrio extends Platform<string> { |
| 58 | + constructor(options?: PlatformOptions<string>) { |
| 59 | + super(options, DEFAULT_BASE_URL); |
| 60 | + } |
| 61 | + |
| 62 | + /** Fetches a problem from LibreOJ using API. */ |
| 63 | + override async getProblem(id: string): Promise<Problem> { |
| 64 | + const displayId = Number.parseInt(id); |
| 65 | + if (Number.isNaN(displayId)) |
| 66 | + throw new NotFoundError('problem'); |
| 67 | + |
| 68 | + let data: any; |
| 69 | + try { |
| 70 | + data = await this.ofetch('/api/problem/getProblem', { |
| 71 | + method: 'POST', |
| 72 | + body: { |
| 73 | + displayId, |
| 74 | + localizedContentsOfLocale: this.locale || 'zh_CN', |
| 75 | + tagsOfLocale: this.locale || 'zh_CN', |
| 76 | + samples: true, |
| 77 | + judgeInfo: true, |
| 78 | + judgeInfoToBePreprocessed: true, |
| 79 | + statistics: false, |
| 80 | + discussionCount: false, |
| 81 | + permissionOfCurrentUser: false, |
| 82 | + lastSubmissionAndLastAcceptedSubmission: false, |
| 83 | + }, |
| 84 | + responseType: 'json', |
| 85 | + }); |
| 86 | + } catch (e) { |
| 87 | + throw new UnOJError(`Failed to fetch problem ${id}`, { cause: e }); |
| 88 | + } |
| 89 | + |
| 90 | + if (data.error === 'NO_SUCH_PROBLEM') |
| 91 | + throw new NotFoundError('problem'); |
| 92 | + if (!data.meta || !data.localizedContentsOfLocale) |
| 93 | + throw new UnexpectedResponseError(data); |
| 94 | + |
| 95 | + return { |
| 96 | + id, |
| 97 | + type: data.meta.type, |
| 98 | + title: data.localizedContentsOfLocale.title, |
| 99 | + link: `https://loj.ac/p/${displayId}`, |
| 100 | + description: JSON.stringify(data.localizedContentsOfLocale.contentSections), |
| 101 | + |
| 102 | + samples: data.samples.map((sample: any) => ({ |
| 103 | + input: sample.inputData, |
| 104 | + output: sample.outputData, |
| 105 | + })), |
| 106 | + timeLimit: data.judgeInfo.timeLimit, |
| 107 | + memoryLimit: data.judgeInfo.memoryLimit * 1024 * 1024, |
| 108 | + tags: data.tagsOfLocale || [], |
| 109 | + difficulty: undefined, |
| 110 | + }; |
| 111 | + } |
| 112 | +} |
0 commit comments