"""电子书种子:把 res/ 下已有的三本书挂到教材上。 幂等:只补不覆盖,管理员在后台重新上传的文件不会被种子冲掉。 """ from __future__ import annotations from pathlib import Path from sqlalchemy.orm import Session from database import REPO_ROOT from models import Textbook from services import ebooks as store RES_ROOT = REPO_ROOT / "res" # res/ 里的文件名带书目后缀,展示时用干净的名称 PRINCETON = { "name": "普林斯顿微积分读本(修订版)", "author": "阿德里安·班纳 (Adrian Banner)", "publisher": "人民邮电出版社", "grade": "高中至大学先修", "description": "面向微积分入门的系统辅导书,覆盖极限、导数、积分与级数," "按考点组织,适合自学与考前查漏补缺。", "resource": "普林斯顿微积分读本(修订版)", "display": "普林斯顿微积分读本(修订版).epub", } # 已有教材 → res/ 中的 PDF(按教材名前缀匹配) PDF_LINKS = [ ("函数和图像", "函数和图像", "函数和图像(盖尔范德中学生数学思维丛书).pdf"), ("三角函数", "三角函数", "三角函数(盖尔范德中学生数学思维丛书).pdf"), ] def _find_resource(prefix: str, suffix: str) -> Path | None: """res/ 下的文件名带作者与来源后缀,只按标题前缀匹配。""" if not RES_ROOT.is_dir(): return None for path in sorted(RES_ROOT.iterdir()): if ( path.is_file() and path.suffix.lower() == suffix and path.name.startswith(prefix) ): return path return None def ensure_ebooks(db: Session) -> None: created = False textbook = ( db.query(Textbook).filter(Textbook.name == PRINCETON["name"]).first() ) if textbook is None: position = ( db.query(Textbook).count() ) textbook = Textbook( name=PRINCETON["name"], author=PRINCETON["author"], publisher=PRINCETON["publisher"], grade=PRINCETON["grade"], description=PRINCETON["description"], position=position, ) db.add(textbook) db.commit() created = True if created: epub = _find_resource(PRINCETON["resource"], ".epub") if epub is not None and not textbook.ebook_file: store.attach_local_file( db, textbook, epub, display_name=PRINCETON["display"] ) for name_prefix, file_prefix, display in PDF_LINKS: textbook = ( db.query(Textbook) .filter(Textbook.name.startswith(name_prefix)) .first() ) if textbook is None or textbook.ebook_file: continue pdf = _find_resource(file_prefix, ".pdf") if pdf is None: continue store.attach_local_file(db, textbook, pdf, display_name=display)