Skip to content

Commit

Permalink
🔨重构文档任务点实现
Browse files Browse the repository at this point in the history
  • Loading branch information
SocialSisterYi committed Aug 17, 2023
1 parent a8fa63b commit 9cb691f
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 100 deletions.
9 changes: 1 addition & 8 deletions Dockerfile
Expand Up @@ -3,14 +3,7 @@ FROM python:3.10
ENV TZ="Asia/Shanghai"

# 安装必要组件
RUN rm -f /etc/apt/sources.list && \
echo 'deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free' >> /etc/apt/sources.list && \
echo 'deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free' >> /etc/apt/sources.list && \
echo 'deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free' >> /etc/apt/sources.list && \
echo 'deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free' >> /etc/apt/sources.list && \
pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple && \
apt update && \
apt-get -y upgrade && \
RUN apt update && \
apt-get -y install libgl1-mesa-glx && \
pip install poetry

Expand Down
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -258,6 +258,8 @@ Enncy 题库,使用前请注册并获取 Token 填写在配置文件中(第

若配置文件的`exam->confirm_submit``true`那么在交卷前会提示确认,否则将自动交卷

如需导出题库到 export 路径,需在考试选择界面输入`e`+序号

![](imgs/demo4.png)

## 💡About Repo Name
Expand Down
28 changes: 14 additions & 14 deletions cxapi/chapters.py
Expand Up @@ -35,9 +35,9 @@ class ChapterContainer:
acc: AccountInfo
chapters: list[ChapterModel]
# 课程参数
courseid: int # 课程 id
course_id: int # 课程 id
name: str # 课程名
clazzid: int # 班级 id
clazz_id: int # 班级 id
cpi: int

tui_index: int # TUI 列表指针索引值
Expand All @@ -55,8 +55,8 @@ def __init__(
self.logger = Logger("Chapters")
self.session = session
self.acc = acc
self.courseid = courseid
self.clazzid = clazzid
self.course_id = courseid
self.clazz_id = clazzid
self.name = name
self.cpi = cpi
self.chapters = chapters
Expand All @@ -67,7 +67,7 @@ def __len__(self) -> int:
return len(self.chapters)

def __repr__(self) -> str:
return f"<ClassChapters id={self.courseid} name={self.name} count={len(self)}>"
return f"<ClassChapters id={self.course_id} name={self.name} count={len(self)}>"

def is_finished(self, index: int) -> bool:
"判断当前章节的任务点是否全部完成"
Expand Down Expand Up @@ -123,11 +123,11 @@ def fetch_point_status(self) -> None:
data={
"view": "json",
"nodes": ",".join(str(c.chapter_id) for c in self.chapters),
"clazzid": self.clazzid,
"clazzid": self.clazz_id,
"time": get_ts(),
"userid": self.acc.puid,
"cpi": self.cpi,
"courseid": self.courseid,
"courseid": self.course_id,
},
)
resp.raise_for_status()
Expand All @@ -148,7 +148,7 @@ def fetch_points_by_index(self, index: int) -> list[TaskPointType]:
"以课程序号拉取对应“章节”的任务节点卡片资源"
params = {
"id": self.chapters[index].chapter_id,
"courseid": self.courseid,
"courseid": self.course_id,
"fields": "id,parentnodeid,indexorder,label,layer,name,begintime,createtime,lastmodifytime,status,jobUnfinishedCount,clickcount,openlock,card.fields(id,knowledgeid,title,knowledgeTitile,description,cardorder).contentcard(all)",
"view": "json",
"token": "4faa8662c59590c6f43ae9fe5b002b42",
Expand Down Expand Up @@ -198,10 +198,10 @@ def fetch_points_by_index(self, index: int) -> list[TaskPointType]:
session=self.session,
acc=self.acc,
card_index=card_index,
course_id=self.courseid,
course_id=self.course_id,
knowledge_id=self.chapters[index].chapter_id,
object_id=json_data["objectid"],
clazz_id=self.clazzid,
clazz_id=self.clazz_id,
cpi=self.cpi,
)
)
Expand All @@ -215,12 +215,12 @@ def fetch_points_by_index(self, index: int) -> list[TaskPointType]:
session=self.session,
acc=self.acc,
card_index=card_index,
course_id=self.courseid,
course_id=self.course_id,
work_id=json_data["workid"],
school_id=json_data.get("schoolid"),
job_id=json_data["_jobid"],
knowledge_id=self.chapters[index].chapter_id,
clazz_id=self.clazzid,
clazz_id=self.clazz_id,
cpi=self.cpi,
)
)
Expand All @@ -234,9 +234,9 @@ def fetch_points_by_index(self, index: int) -> list[TaskPointType]:
session=self.session,
acc=self.acc,
card_index=card_index,
course_id=self.courseid,
course_id=self.course_id,
knowledge_id=self.chapters[index].chapter_id,
clazz_id=self.clazzid,
clazz_id=self.clazz_id,
cpi=self.cpi,
object_id=json_data["objectid"],
)
Expand Down
69 changes: 28 additions & 41 deletions cxapi/jobs/document.py
@@ -1,17 +1,14 @@
import json
import re
import time

from bs4 import BeautifulSoup
from rich.json import JSON
from rich.layout import Layout
from rich.panel import Panel

from logger import Logger

from .. import get_ts
from ..schema import AccountInfo
from ..session import SessionWraper
from ..exception import APIError

# SSR页面-客户端章节任务卡片
PAGE_MOBILE_CHAPTER_CARD = "https://mooc1-api.chaoxing.com/knowledge/cards"
Expand All @@ -27,13 +24,13 @@ class PointDocumentDto:
session: SessionWraper
acc: AccountInfo
# 基本参数
clazzid: int
courseid: int
knowledgeid: int
clazz_id: int
course_id: int
knowledge_id: int
card_index: int # 卡片索引位置
cpi: int
# 文档参数
objectid: str
object_id: str
jobid: str
title: str
jtoken: str
Expand All @@ -52,21 +49,25 @@ def __init__(
self.logger = Logger("PointDocument")
self.session = session
self.acc = acc
self.clazzid = clazz_id
self.courseid = course_id
self.knowledgeid = knowledge_id
self.clazz_id = clazz_id
self.course_id = course_id
self.knowledge_id = knowledge_id
self.card_index = card_index
self.objectid = object_id
self.object_id = object_id
self.cpi = cpi

def __str__(self) -> str:
return f"PointDocument(title={self.title} jobid={self.object_id} dtoken={self.jtoken})"

def pre_fetch(self) -> bool:
"预拉取文档 返回是否需要完成"
"""预拉取文档 返回是否需要完成
"""
resp = self.session.get(
PAGE_MOBILE_CHAPTER_CARD,
params={
"clazzid": self.clazzid,
"courseid": self.courseid,
"knowledgeid": self.knowledgeid,
"clazzid": self.clazz_id,
"courseid": self.course_id,
"knowledgeid": self.knowledge_id,
"num": self.card_index,
"isPhone": 1,
"control": "true",
Expand All @@ -87,7 +88,7 @@ def pre_fetch(self) -> bool:
# 定位资源objectid
for point in attachment["attachments"]:
if prop := point.get("property"):
if prop.get("objectid") == self.objectid:
if prop.get("objectid") == self.object_id:
break
else:
self.logger.warning("定位任务资源失败")
Expand All @@ -104,41 +105,27 @@ def pre_fetch(self) -> bool:
self.logger.error(f"预拉取失败")
raise RuntimeError("文档预拉取出错")

def fetch(self) -> bool:
"拉取文档"
return True # 文档类型无需二次拉取

def __report_reading(self):
"上报文档阅读记录"
def report(self):
"""上报文档阅读记录
"""
resp = self.session.get(
API_DOCUMENT_READINGREPORT,
params={
"jobid": self.jobid,
"knowledgeid": self.knowledgeid,
"courseid": self.courseid,
"clazzid": self.clazzid,
"knowledgeid": self.knowledge_id,
"courseid": self.course_id,
"clazzid": self.clazz_id,
"jtoken": self.jtoken,
"_dc": get_ts(),
},
)
resp.raise_for_status()
json_content = resp.json()
self.logger.debug(f"上报 resp: {json_content}")
if error := json_content.get("error"):
self.logger.error(f"文档上报失败")
raise APIError(error)
self.logger.info(f"文档上报成功")
return json_content

def watch(self, tui_ctx: Layout) -> None:
"开始模拟阅读文档"
inspect = Layout()
tui_ctx.split_column(Panel(f"模拟浏览:{self.title}", title="正在模拟浏览"), inspect)
report_result = self.__report_reading()
j = JSON.from_data(report_result, ensure_ascii=False)
if report_result["status"]:
inspect.update(Panel(j, title="上报成功", border_style="green"))
self.logger.info(f"文档浏览上报成功 [{self.title}(O.{self.objectid}/J.{self.jobid})]")
else:
self.logger.warning(f"文档浏览上报失败 [{self.title}(O.{self.objectid}/J.{self.jobid})]")
inspect.update(Panel(j, title="上报失败", border_style="red"))
time.sleep(1.0)


__all__ = ["PointDocumentDto"]
44 changes: 22 additions & 22 deletions cxapi/jobs/video.py
Expand Up @@ -30,17 +30,17 @@ class PointVideoDto:
session: SessionWraper
acc: AccountInfo
# 基本参数
clazzid: int
courseid: int
knowledgeid: int
clazz_id: int
course_id: int
knowledge_id: int
card_index: int # 卡片索引位置
cpi: int
# 视频参数
objectid: str
object_id: str
fid: int
dtoken: str
duration: int # 视频时长
jobid: str
job_id: str
otherInfo: str
title: str # 视频标题
rt: float
Expand All @@ -59,24 +59,24 @@ def __init__(
self.logger = Logger("PointVideo")
self.session = session
self.acc = acc
self.clazzid = clazz_id
self.courseid = course_id
self.knowledgeid = knowledge_id
self.clazz_id = clazz_id
self.course_id = course_id
self.knowledge_id = knowledge_id
self.card_index = card_index
self.objectid = object_id
self.object_id = object_id
self.cpi = cpi

def __str__(self) -> str:
return f"PointVideo(title={self.title} duration={self.duration} objectid={self.objectid} dtoken={self.dtoken} jobid={self.jobid})"
return f"PointVideo(title={self.title} duration={self.duration} objectid={self.object_id} dtoken={self.dtoken} jobid={self.job_id})"

def pre_fetch(self) -> bool:
"预拉取视频 返回是否需要完成"
resp = self.session.get(
PAGE_MOBILE_CHAPTER_CARD,
params={
"clazzid": self.clazzid,
"courseid": self.courseid,
"knowledgeid": self.knowledgeid,
"clazzid": self.clazz_id,
"courseid": self.course_id,
"knowledgeid": self.knowledge_id,
"num": self.card_index,
"isPhone": 1,
"control": "true",
Expand All @@ -98,13 +98,13 @@ def pre_fetch(self) -> bool:
# 定位资源objectid
for point in attachment["attachments"]:
if prop := point.get("property"):
if prop.get("objectid") == self.objectid:
if prop.get("objectid") == self.object_id:
break
else:
self.logger.warning("定位任务资源失败")
return False
if jobid := point.get("jobid"):
self.jobid = jobid
self.job_id = jobid
self.otherInfo = point["otherInfo"]
self.rt = float(point["property"].get("rt", 0.9))
self.logger.info("预拉取成功")
Expand All @@ -120,7 +120,7 @@ def fetch(self) -> bool:
"""拉取视频
"""
resp = self.session.get(
f"{API_CHAPTER_CARD_RESOURCE}/{self.objectid}",
f"{API_CHAPTER_CARD_RESOURCE}/{self.object_id}",
params={
"k": self.fid,
"flag": "normal",
Expand Down Expand Up @@ -155,18 +155,18 @@ def play_report(self, playing_time: int) -> dict:
"playingTime": playing_time,
"duration": self.duration,
# 'akid': None,
"jobid": self.jobid,
"jobid": self.job_id,
"clipTime": f"0_{self.duration}",
"clazzId": self.clazzid,
"objectId": self.objectid,
"clazzId": self.clazz_id,
"objectId": self.object_id,
"userid": self.acc.puid,
"isdrag": "0",
"enc": md5(
"[{}][{}][{}][{}][{}][{}][{}][{}]".format(
self.clazzid,
self.clazz_id,
self.acc.puid,
self.jobid,
self.objectid,
self.job_id,
self.object_id,
playing_time * 1000,
"d_yHJ!$pdA~5",
self.duration * 1000,
Expand Down
6 changes: 4 additions & 2 deletions cxapi/jobs/work.py
Expand Up @@ -61,8 +61,9 @@ def parse_question(question_node: Tag) -> QuestionModel:
in options_node.select_one("div.choose-desc").cc.strings
)
.strip()
.replace("\u200b", "")
.replace("\xa0", "")
.replace("\u200b", "")
.replace("\u3000", "")
)
options[option_key] = option_value
case QuestionType.填空题:
Expand All @@ -89,8 +90,9 @@ def parse_question(question_node: Tag) -> QuestionModel:

question_value = (question_value
.strip()
.replace("\u200b", "")
.replace("\xa0", "")
.replace("\u200b", "")
.replace("\u3000", "")
)

return QuestionModel(
Expand Down

0 comments on commit 9cb691f

Please sign in to comment.