diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8bc9fd7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +env/ +venv/ +.env/ +.venv/ + +.idea/ +__pycache__/ +*.py[cod] +*.pyo +*.pyd +*.pyc +*.pdb +*.json \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8b11b6e..cb90676 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ __pycache__/ */__pycache__/ *.py[cod] *$py.class +env diff --git a/Dockerfile b/Dockerfile index 05ecf8a..8551815 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11 +FROM python:3.11-slim WORKDIR /app RUN apt-get update &&\ apt-get install -y curl diff --git a/main.py b/main.py index 1934056..a7efa7b 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,5 @@ import argparse - +import os import gradio as gr from loguru import logger @@ -8,7 +8,7 @@ from tab.order import order_tab from tab.problems import problems_tab from tab.settings import setting_tab - +from tab.log import log_tab header = """ # CPP 抢票🌈 @@ -30,11 +30,17 @@ if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument("--port", type=int, default=7860, help="server port") + parser.add_argument("--port", type=int, default=11451, help="server port") parser.add_argument("--share", type=bool, default=False, help="create a public link") args = parser.parse_args() + LOG_PATH = (os.environ.get("LOG_PATH", "logs/app.log")) + os.remove(LOG_PATH) if os.path.exists(LOG_PATH) else None + logger.remove() + logger.add(LOG_PATH, rotation="1 MB", retention="7 days", encoding="utf-8") + logger.add(lambda msg: print(msg, end=""), level="INFO") logger.add("app.log") + with gr.Blocks(head=short_js, css=custom_css) as demo: gr.Markdown(header) with gr.Tab("配置"): @@ -47,7 +53,14 @@ login_tab() with gr.Tab("常见问题"): problems_tab() + with gr.Tab("日志"): + log_tab() print("CPP账号的登录是在此控制台,请留意提示!!") print("点击下面的网址运行程序 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓") - demo.launch(share=args.share, inbrowser=True) + demo.launch(share=args.share, + server_name="0.0.0.0", + server_port=7860, + inbrowser=False, + allowed_paths=["/usr/local/bin"] + ) diff --git a/tab/log.py b/tab/log.py new file mode 100644 index 0000000..e057046 --- /dev/null +++ b/tab/log.py @@ -0,0 +1,19 @@ +import gradio as gr +import os + +LOG_PATH = (os.environ.get("LOG_PATH", "logs/app.log")) +def read_last_logs(n=1000): + if not os.path.exists(LOG_PATH): + return "No logs found." + with open(LOG_PATH, "r", encoding="utf-8") as f: + lines = f.readlines() + return "".join(lines[-n:]) + +def log_tab(): + log_textbox = gr.Textbox(label="最近日志", lines=20, interactive=False) + refresh_btn = gr.Button("刷新日志") + log_file_download = gr.File(label="下载完整日志", value=LOG_PATH, interactive=False) + + refresh_btn.click(fn=read_last_logs, inputs=None, outputs=log_textbox) + timer = gr.Timer(5.0) + timer.tick(fn=read_last_logs, outputs=log_textbox) \ No newline at end of file diff --git a/tab/login.py b/tab/login.py index 04b1a46..866b228 100644 --- a/tab/login.py +++ b/tab/login.py @@ -35,11 +35,10 @@ def login_tab(): info="此窗口为输出信息", label="输出信息", interactive=False ) with gr.Row(): - upload_ui = gr.UploadButton(label="导入") - add_btn = gr.Button("登录") + upload_ui = gr.UploadButton(label="导入配置文件") def upload_file(filepath): - main_request.cookieManager.db.delete("cookie") + main_request.cookieManager.reset() yield ["已经注销,请选择登录信息文件", gr.update(), gr.update()] try: configDB.insert("cookie_path", filepath) @@ -52,20 +51,35 @@ def upload_file(filepath): upload_ui.upload(upload_file, [upload_ui], [info_ui, username_ui, gr_file_ui]) - def add(): - main_request.cookieManager.db.delete("cookie") - yield ["已经注销,在控制台(终端)登录", gr.update(value="未登录"), - gr.update(value=configDB.get("cookie_path"))] + with gr.Row(): + user_input = gr.Textbox(label="用户名") + pass_input = gr.Textbox(label="密码", type="password") + login_btn = gr.Button("使用账号密码登录") + logout_btn = gr.Button("注销登录") + + def login(username, password): + main_request.cookieManager.reset() + yield ["已经注销,请重新登录", gr.update(value="未登录"), gr.update(value=configDB.get("cookie_path"))] try: - main_request.cookieManager.get_cookies_str_force() + main_request.cookieManager.login_by_phone_passwd(username, password) name = main_request.get_request_name() - yield [f"登录成功", gr.update(value=name), gr.update(value=configDB.get("cookie_path"))] + if name == '未登录': + yield ["登录失败,请检查账号密码", gr.update(value="未登录"), gr.update(value=configDB.get("cookie_path"))] + else: + yield [gr.update(value="登录成功"), gr.update(value=name), gr.update(value=configDB.get("cookie_path"))] except Exception: name = main_request.get_request_name() yield ["登录出现错误", gr.update(value=name), gr.update(value=configDB.get("cookie_path"))] - - add_btn.click( - fn=add, + def logout(): + main_request.cookieManager.reset() + yield ["已经注销,重新登录", gr.update(value="未登录"), gr.update(value=configDB.get("cookie_path"))] + login_btn.click( + fn=login, + inputs=[user_input, pass_input], + outputs=[info_ui, username_ui, gr_file_ui] + ) + logout_btn.click( + fn=logout, inputs=None, outputs=[info_ui, username_ui, gr_file_ui] ) diff --git a/util/CookieManager.py b/util/CookieManager.py index da9475c..4750b41 100644 --- a/util/CookieManager.py +++ b/util/CookieManager.py @@ -7,14 +7,8 @@ class CookieManager: def __init__(self, config_file_path): self.db = KVDatabase(config_file_path) - @logger.catch - def _login_and_save_cookies( - self, login_url="https://cp.allcpp.cn/#/login/main" - ): - print("开始填写登录信息") - phone = input("输入手机号:") - password = input("输入密码:") + def login_by_phone_passwd(self, phone, password): login_url = "https://user.allcpp.cn/api/login/normal" headers = { 'accept': 'application/json, text/plain, */*', @@ -31,22 +25,40 @@ def _login_and_save_cookies( 'sec-fetch-site': 'same-site', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0' } - while True: - payload = f"account={phone}&password={password}&phoneAccountBindToken=undefined&thirdAccountBindToken=undefined" - response = requests.request("POST", login_url, headers=headers, data=payload) + payload = f"account={phone}&password={password}&phoneAccountBindToken=undefined&thirdAccountBindToken=undefined" + response = requests.request("POST", login_url, headers=headers, data=payload) + if response.status_code != 200: + raise RuntimeError(f"登录失败,状态码 {response.status_code},响应内容:{response.text[:100]}") + try: res_json = response.json() - logger.info(f"登录响应体: {res_json}") - if "token" in res_json: - cookies_dict = response.cookies.get_dict() - logger.info(f"cookies: {cookies_dict}") - self.db.insert("cookie", cookies_dict) - self.db.insert("password", password) - self.db.insert("phone", phone) - - return response.cookies - else: - phone = input("输入手机号:") - password = input("输入密码:") + except Exception as e: + raise RuntimeError(f"登录返回无法解析为 JSON:{e}\n响应内容:{response.text[:200]}") + logger.info(f"登录响应体: {res_json}") + if "token" in res_json and res_json["token"] is not None: + cookies_dict = response.cookies.get_dict() + logger.success("登录成功") + logger.info(f"cookies: {cookies_dict}") + self.db.insert("cookie", cookies_dict) + self.db.insert("password", password) + self.db.insert("phone", phone) + return response.cookies + else: + logger.error("登录失败,请检查账号密码是否正确") + return None + + @logger.catch + def _login_and_save_cookies( + self, login_url="https://cp.allcpp.cn/#/login/main" + ): + logger.info("开始填写登录信息") + phone = input("输入手机号:") + password = input("输入密码:") + while self.login_by_phone_passwd(phone, password) is None: + logger.error("登录失败,请检查账号密码是否正确") + phone = input("输入手机号:") + password = input("输入密码:") + logger.success("登录成功") + def refreshToken(self): login_url = "https://user.allcpp.cn/api/login/normal" @@ -114,3 +126,8 @@ def set_config_value(self, name, value): def get_cookies_str_force(self): self._login_and_save_cookies() return self.get_cookies_str() + + def reset(self): + self.db.delete("cookie") + self.db.delete("password") + self.db.delete("phone")