Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions src/tchmaterial_parser/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typing import NamedTuple
from urllib.parse import urlparse, parse_qs

from .network import headers, request_headers, session
from .network import REQUEST_TIMEOUT, headers, request_headers, session
from .platform_utils import print_error

class ResourceInfo(NamedTuple):
Expand All @@ -14,6 +14,7 @@ class ResourceInfo(NamedTuple):
file_format: str
chapters: list[dict]
edition: str | None = None
relative_dir: tuple[str, ...] = () # 按资源树层级(学段/学科/版本)分类存放的子目录

def get_edition_name(resource_data: dict) -> str | None:
"""读取资源分类中的教材版别,例如 “人教版”“北师大版”。"""
Expand All @@ -22,6 +23,17 @@ def get_edition_name(resource_data: dict) -> str | None:
return tag["tag_name"]
return None

TAG_DIMENSIONS = ("zxxxd", "zxxxk", "zxxbb") # 学段、学科、版本,与资源树的分类层级一致

def get_relative_dir(resource_data: dict) -> tuple[str, ...]:
"""按资源树层级从 tag_list 提取分类目录(学段/学科/版本),供批量下载时分类存放。"""
names: dict[str, str] = {}
for tag in resource_data.get("tag_list") or []:
dimension = tag.get("tag_dimension_id")
if dimension in TAG_DIMENSIONS and tag.get("tag_name") and dimension not in names:
names[dimension] = tag["tag_name"]
return tuple(names[dimension] for dimension in TAG_DIMENSIONS if dimension in names)

def combine_resource_title(root_title: str | None, resource_title: str) -> str:
"""组合专题标题与实际资源标题,并避免平台重复标题造成超长文件名。"""
if not root_title:
Expand Down Expand Up @@ -128,6 +140,7 @@ def parse(url: str, bookmarks: bool) -> list[ResourceInfo] | None: # 解析资

data: dict = response.json()
root_edition = get_edition_name(data)
root_dir = get_relative_dir(data)

# 3. 获取资源标题、下载链接及章节目录
def get_resource_info(resource_data: dict, root_title: str | None = None, edition: str | None = None) -> ResourceInfo | None:
Expand Down Expand Up @@ -192,7 +205,11 @@ def get_resource_info(resource_data: dict, root_title: str | None = None, editio
if mapping_url:
# a. 下载 mapping 文件获取页码和 ebook_id。
# mapping 也在 ndr-private 上,必须按 URL 现算 X-ND-AUTH,不能用全局占位头。
map_resp = session.get(mapping_url, headers=request_headers(mapping_url))
map_resp = session.get(
mapping_url,
headers=request_headers(mapping_url),
timeout=REQUEST_TIMEOUT,
)
map_data: dict = map_resp.json()
ebook_id: str = map_data.get("ebook_id")

Expand Down Expand Up @@ -251,6 +268,7 @@ def process_tree_nodes(nodes: list[dict]) -> list[dict]:
resource_format,
chapters,
edition or get_edition_name(resource_data),
get_relative_dir(resource_data) or root_dir,
)

def get_audio_info(audio_data: dict, root_title: str | None = None, edition: str | None = None) -> ResourceInfo | None: # 解析教材关联的音频资源(如英语教材听力)
Expand Down Expand Up @@ -284,6 +302,7 @@ def get_audio_info(audio_data: dict, root_title: str | None = None, edition: str
resource_format,
[],
edition or get_edition_name(audio_data),
get_relative_dir(audio_data) or root_dir,
)

if content_type == "thematic_course": # 专题课程
Expand Down
2 changes: 1 addition & 1 deletion src/tchmaterial_parser/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def on_description_resize(event: tk.Event) -> None: # 窗口宽度变化时,
copy_btn.pack(side="right", padx=(0, scaled(8)))

# 下载相关的控件全部就位后,写入下载面板模块,供其中的解析与下载流程使用
download_panel.bind_widgets(url_text, bookmark_var, download_btn, download_progress_bar, progress_label)
download_panel.bind_widgets(url_text, bookmark_var, download_btn, copy_btn, download_progress_bar, progress_label)

# 最后打包内容区,使其占据剩余的全部空间
paned.pack(side="top", fill="both", expand=True, pady=(scaled(14), 0))
Expand Down
2 changes: 2 additions & 0 deletions src/tchmaterial_parser/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
session = requests.Session() # 初始化请求
session.trust_env = False # 不读取系统或环境变量中的代理配置

REQUEST_TIMEOUT = (10, 60) # 连接 / 相邻两次收数据的超时秒数;requests 没有全局默认超时,缺失时卡住的请求会永久挂起

headers = { # 设置请求头部,包含认证信息
"Authorization": "Bearer 0",
"Origin": "https://basic.smartedu.cn",
Expand Down
Loading