Newer
Older
thu-learn-downloader-optimized / thu_learn_downloader / client / learn.py
import functools
import re
from collections.abc import Sequence

from bs4 import BeautifulSoup, Tag
from playwright.sync_api import sync_playwright
from requests import Response
from requests.cookies import RequestsCookieJar

from thu_learn_downloader.common.typing import cast
from . import url
from .client import Client, Language
from .semester import Semester


class Learn:
    client: Client

    def __init__(self, language: Language = Language.ENGLISH, *args, **kwargs) -> None:
        self.client = Client(language, *args, **kwargs)

    def login(self, username: str, password: str) -> None:
        response: Response = self.client.get(url=url.make_url(), verify=False)
        soup: BeautifulSoup = BeautifulSoup(
            markup=response.text, features="html.parser"
        )
        login_button: Tag = cast(Tag, soup.select_one(selector="#loginButtonId"))
        onclick: str = cast(str, login_button["onclick"])
        login_url: str = cast(str, re.search(r"'(https?://[^']+)'", onclick).group(1))

        jar = RequestsCookieJar()

        with sync_playwright() as p:
            browser = p.chromium.launch(headless=False)
            context = browser.new_context()
            page = context.new_page()
            page.goto(login_url)
            page.fill("#i_user", username)
            page.fill("#i_pass", password)
            page.evaluate("doLogin()")

            page.wait_for_url(re.compile(r"learn\.tsinghua\.edu\.cn/.*"), timeout=300_000)

            cookies = context.cookies()
            for cookie in cookies:
                jar.set(
                    name=cookie['name'],
                    value=cookie['value'],
                    domain=cookie.get('domain'),
                    path=cookie.get('path', '/'),
                )

            browser.close()

        self.client.cookies.update(jar)

    @functools.cached_property
    # def semesters(self) -> Sequence[Semester]:
    #     return [
    #         Semester(client=self.client, id=result)
    #         for result in self.client.get_with_token(
    #             url=url.make_url(path="/b/wlxt/kc/v_wlkc_xs_xktjb_coassb/queryxnxq")
    #         ).json()
    #     ]
    def semesters(self) -> Sequence[Semester]:
        response = self.client.get_with_token(
            url=url.make_url(path="/b/wlxt/kc/v_wlkc_xs_xktjb_coassb/queryxnxq")
        )

        if response.status_code != 200:
            print("Request failed with status:", response.status_code)
            return []

        try:
            data = response.json()
            print("Parsed JSON:", data)  # Debugging output

            # Filter out None values
            filtered_data = [item for item in data if item is not None]
        except Exception as e:
            print("JSON decoding error:", e)
            return []

        return [Semester(client=self.client, id=result) for result in filtered_data]