Newer
Older
thu-learn-downloader-optimized / thu_learn_downloader / client / course.py
from collections.abc import Sequence
from typing import Any

from pydantic import Field
from requests import Response

from . import url
from .client import MAX_SIZE, Client
from .document import Document, DocumentClass
from .homework import Homework
from .model import BaseModel


class Course(BaseModel):
    client: Client = Field(exclude=True)
    id: str = Field(alias="wlkcid")
    chinese_name: str = Field(alias="kcm")
    course_number: str = Field(alias="kch")
    english_name: str = Field(alias="ywkcm")
    name: str = Field(alias="zywkcm")
    teacher_name: str = Field(alias="jsm")
    teacher_number: str = Field(alias="jsh")

    @property
    def document_classes(self) -> Sequence[DocumentClass]:
        
        response = self.client.get_with_token(
        url=url.make_url(path="/b/wlxt/kj/wlkc_kjflb/student/pageList"),
        params={"wlkcid": self.id}
        )

        try:
            data = response.json()
        except ValueError:
            print(f"[ERROR] Invalid JSON response for course {self.id}. Skipping...")
            return []  # Skip if response is not JSON

        if not isinstance(data, dict) or "object" not in data or not data["object"]:
            print(f"[WARNING] Skipping course {self.id}: No document data available.")
            return []  # Skip if 'object' is missing or None

        if data.get("result") == "error":
            print(f"[WARNING] Skipping course {self.id}: {data.get('msg', 'Unknown error')}")
            return []  # Skip if permission denied
        
        return [DocumentClass(client=self.client, **result) for result in data["object"]["rows"]]

    @property
    def documents(self) -> Sequence[Document]:
        try:
            response = self.client.get_with_token(
                url=url.make_url(
                    path="/b/wlxt/kj/wlkc_kjxxb/student/kjxxbByWlkcidAndSizeForStudent"
                ),
                params={"wlkcid": self.id, "size": MAX_SIZE},
            )
            data = response.json()
        except Exception as e:
            print(f"[ERROR] Failed to fetch documents for course {self.id}: {e}")
            return []  # Return empty list to avoid crash

        # Ensure 'object' exists and is iterable
        if not isinstance(data, dict) or "object" not in data or not isinstance(data["object"], list):
            print(f"[WARNING] No valid documents for course {self.id}. Skipping...")
            return []

        # Convert to Document objects and sort
        documents: Sequence[Document] = [
            Document(client=self.client, **result) for result in data["object"]
        ]
        documents.sort(key=lambda document: document.title)
        documents.sort(key=lambda document: document.upload_time)

        return documents


    @property
    def homeworks(self) -> Sequence[Homework]:
        return [
            *self._homeworks_at_url(
                url=url.make_url(
                    path="/b/wlxt/kczy/zy/student/index/zyListWj",
                    query={"wlkcid": self.id, "size": MAX_SIZE},
                ),
            ),
            *self._homeworks_at_url(
                url=url.make_url(
                    path="/b/wlxt/kczy/zy/student/index/zyListYjwg",
                    query={"wlkcid": self.id, "size": MAX_SIZE},
                ),
            ),
            *self._homeworks_at_url(
                url=url.make_url(
                    path="/b/wlxt/kczy/zy/student/index/zyListYpg",
                    query={"wlkcid": self.id, "size": MAX_SIZE},
                ),
            ),
        ]

    def _homeworks_at_url(self, url: str) -> Sequence[Homework]:
        resp: Response = self.client.get_with_token(url=url)
        json: dict[str, Any] = resp.json()
        results: Sequence[dict[str, Any]] = json["object"]["aaData"] or []
        return [
            Homework.from_json(client=self.client, json=result) for result in results
        ]