From a99ace395c223b236f62b79bf6ebc6a389938cc3 Mon Sep 17 00:00:00 2001 From: yzqzss Date: Sun, 21 Apr 2024 20:49:25 +0800 Subject: [PATCH] v1.0.0 --- .gitignore | 2 + huashijie/hsj_api.py | 52 +++++++++ huashijie/huashijie_work.py | 127 +++++++++++++++++++++ huashijie/util/archivist.py | 19 ++++ huashijie/util/device.py | 15 +++ huashijie/util/task.py | 40 +++++++ huashijie/util/tracker.py | 206 +++++++++++++++++++++++++++++++++++ huashijie/util/unique_str.py | 18 +++ poetry.lock | 204 ++++++++++++++++++++++++++++++++++ pyproject.toml | 18 +++ 10 files changed, 701 insertions(+) create mode 100644 .gitignore create mode 100644 huashijie/hsj_api.py create mode 100644 huashijie/huashijie_work.py create mode 100644 huashijie/util/archivist.py create mode 100644 huashijie/util/device.py create mode 100644 huashijie/util/task.py create mode 100644 huashijie/util/tracker.py create mode 100644 huashijie/util/unique_str.py create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4edd750 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode +__pycache__ \ No newline at end of file diff --git a/huashijie/hsj_api.py b/huashijie/hsj_api.py new file mode 100644 index 0000000..6a714bc --- /dev/null +++ b/huashijie/hsj_api.py @@ -0,0 +1,52 @@ +import os +import secrets + +import requests + +from huashijie.util.device import XIAOMI_MODELS +from huashijie.util.unique_str import uniquestr + +ss = requests.session() + +workid = 200200 +status_s = {} +while workid and os.path.exists('run'): + r = ss.get( + 'http://app.huashijie.art/api/work/detailV2', + params={ + 'visitorId': '-1', # 当前用户 id,访客是 -1 + 'workId': workid, # 作品 id, 如: 200202585 + 'cur_user_id': '-1', # 当前用户 id,访客 -1 + 'platform': 'android', + 'os_version': secrets.choice([i for i in range(23, 34)]), + 'version_code': '224', + 'device_brand': 'Xiaomi', + 'device_model': secrets.choice(XIAOMI_MODELS), + 'token': '', # 访客传 "" 空字符串即可 + 'channel': 'main', # main 是画世界。还有熊猫绘画 + }, + headers={ + uniquestr('Referer'): '*.painterclub.cn', + uniquestr('Referer'): '*.pandapaint.net', + uniquestr('Referer'): '*.huashijie.art', + 'Connection': 'Keep-Alive', + 'Accept-Encoding': 'gzip', + 'User-Agent': 'okhttp/3.12.0', + }, + ) + r.raise_for_status() + r_json = r.json() + if str(r_json['msg']) not in status_s: + print(r_json) + status_s[str(r_json['msg'])] = r_json + workid = secrets.randbelow(200200) + print(workid, '--->', len(status_s)) + +print('===========') +print(status_s) +# status 1: 正常 +# {"status":43,"msg":"作品不存在"} +# {"status":43,"msg":"非法作品id"} +# {'status': 43, 'msg': '暂无查看该作品的权限'} +# {"status":72,"msg":"作品已删除"} +# {'status': 72, 'msg': '由于作者隐私设置,您没有权限查看此作品'} \ No newline at end of file diff --git a/huashijie/huashijie_work.py b/huashijie/huashijie_work.py new file mode 100644 index 0000000..7ce07df --- /dev/null +++ b/huashijie/huashijie_work.py @@ -0,0 +1,127 @@ +from datetime import datetime +import os +import secrets +import sys +import time +import traceback + +import requests +from requests.adapters import HTTPAdapter + +from huashijie.util.archivist import get_archivist, new_archivist +from huashijie.util.device import XIAOMI_MODELS +from huashijie.util.task import Status, Task +from huashijie.util.tracker import Tracker +from huashijie.util.unique_str import uniquestr + +VERSION = "1.0" + +session = requests.Session() +session.mount("https://", HTTPAdapter(max_retries=3)) +session.mount("http://", HTTPAdapter(max_retries=3)) + +def get_work_detail_r(work_id: int): + r = session.get('http://app.huashijie.art/api/work/detailV2', + params={ + 'visitorId': '-1', # 当前用户 id,访客是 -1 + 'workId': work_id, # 作品 id, 200202585 + 'cur_user_id': '-1', # 当前用户 id,访客 -1 + 'platform': 'android', + 'os_version': secrets.choice([i for i in range(23, 34)]), + 'version_code': '224', + 'device_brand': 'Xiaomi', + 'device_model': secrets.choice(XIAOMI_MODELS), + 'token': '', # 访客传 "" 空字符串即可 + 'channel': 'main', # main 是画世界。还有熊猫绘画 + }, + headers={ + uniquestr('Referer'): '*.painterclub.cn', + uniquestr('Referer'): '*.pandapaint.net', + uniquestr('Referer'): '*.huashijie.art', + 'Connection': 'Keep-Alive', + 'Accept-Encoding': 'gzip', + 'User-Agent': 'okhttp/3.12.0', + }, + ) + return r + +def process(tracker: Tracker, TASK: Task): + + r = get_work_detail_r(TASK.id) + r.raise_for_status() + r_json = r.json() + + TO_INSERT = False + +# status 1: 正常 +# {"status":43,"msg":"作品不存在"} +# {"status":43,"msg":"非法作品id"} +# {'status': 43, 'msg': '暂无查看该作品的权限'} +# {"status":72,"msg":"作品已删除"} +# {'status': 72, 'msg': '由于作者隐私设置,您没有权限查看此作品'} + + if 'status' in r_json: + status = r_json['status'] + if status == 1: + # OK + TO_INSERT = True + item_status = 1 + payload = r_json + elif status in (43, 72): + print(r_json) + TO_INSERT = True + item_status = status + payload = r_json + else: + raise Exception("Unknown status: " + r.text) + else: + raise Exception("Unknown response: " + r.text) + + if TO_INSERT: + tracker.insert_item(item_id=TASK.id, item_status=item_status, payload=payload) + tracker.update_task(task_id=TASK.id, status=Status.DONE) + else: + raise NotImplementedError(r.text) + +def main(): + archivist = get_archivist() or new_archivist() + tracker = Tracker(project_id="huashijie_work", client_version=VERSION, archivist=archivist, session=session) + + while True: + if tracker.project.status.paused: + print("[tracker->client] Project paused, sleep 120s") + time.sleep(120) + continue + if os.path.exists("stop"): + print("[STOP] stop file exists, exit") + return + + TASK_raw = tracker.claim_task() + if TASK_raw is None: + notask_sleep = tracker.project.client.claim_task_delay * 3 + print(f"No tasks available, sleep {notask_sleep:.2f}s") + time.sleep(notask_sleep) + continue + + TASK = Task(**TASK_raw) + + start = time.time() + try: + print('===', datetime.now().strftime("%Y-%m-%d %H:%M:%S"), TASK, '===') + process(tracker=tracker, TASK=TASK) + except Exception as e: + print(f"Task {TASK} failed: {e}") + traceback.print_exc() + + # 抛的异常都会把任务设成 FAIL + tracker.update_task(task_id=TASK.id, status=Status.FAIL) + + if isinstance(e, requests.exceptions.HTTPError): + if e.response.status_code == 403: + print("403") + sys.exit(1) + + print(f"Task {TASK.id} done in {time.time() - start:.2f}s") + +if __name__ == "__main__": + main() diff --git a/huashijie/util/archivist.py b/huashijie/util/archivist.py new file mode 100644 index 0000000..7bfbcfb --- /dev/null +++ b/huashijie/util/archivist.py @@ -0,0 +1,19 @@ +import os + + +def new_archivist(): + print("zh: 未避免您的节点被 ban,请不要在同一个 IP 下多开!") + print("en: To avoid being banned, please do not run concurrently on the same IP!") + print("zh: 第一次运行,请输入可以唯一标识您节点的字符串。(合法字符:字母、数字、-、_)") + print("en: First run, please input a string that can uniquely identify your node. (Legal characters: letters, numbers, -, _)") + with open("ARCHIVIST.conf", "w") as f: + f.write(input("ARCHIVIST: ")) + return get_archivist() + +def get_archivist(): + if not os.path.exists("ARCHIVIST.conf"): + return "" + print("zh: 未避免您的节点被 ban,请不要在同一个 IP 下多开!") + print("en: To avoid being banned, please do not run concurrently on the same IP!") + with open("ARCHIVIST.conf", "r") as f: + return f.read().splitlines()[0].strip() \ No newline at end of file diff --git a/huashijie/util/device.py b/huashijie/util/device.py new file mode 100644 index 0000000..3764861 --- /dev/null +++ b/huashijie/util/device.py @@ -0,0 +1,15 @@ +XIAOMI_MODELS = [ + "M2001J2E", + "M1810E5GG", + "2304FPN6DG", + "23127PN0CC", +] + +XIAOMI_BUILD_NUMBERS = [ + "SKQ1.220303.001", + "SKQ1.211019.001", + "TKQ1.220905.001", + "TKQ1.231108.001", + "SKQ1.240105.001", + "SKQ1.240201.001" +] \ No newline at end of file diff --git a/huashijie/util/task.py b/huashijie/util/task.py new file mode 100644 index 0000000..88e1015 --- /dev/null +++ b/huashijie/util/task.py @@ -0,0 +1,40 @@ +from typing import Optional +from dataclasses import dataclass +from datetime import datetime + +from bson import ObjectId + +class Status: + TODO = "TODO" + PROCESSING = "PROCESSING" + DONE = "DONE" + + TIMEOUT = "TIMEOUT" # 一直 PROCESSING 的任务,超时 + FAIL = "FAIL" + FEZZ = "FEZZ" + """ 特殊: 任务冻结 """ + +@dataclass +class Task: + _id: ObjectId + id: int + status: Status + archivist: str + + claimed_at: Optional[datetime] = None + updated_at: Optional[datetime] = None + + + def __post_init__(self): + assert self.status in Status.__dict__.values() + + def __repr__(self): + return f"Task({self.id}, status={self.status})" + + def __init__(self, _id, id, status, archivist, claimed_at, updated_at): + self._id = _id + self.id = id + self.status = status + self.archivist = archivist + self.claimed_at = claimed_at + self.updated_at = updated_at \ No newline at end of file diff --git a/huashijie/util/tracker.py b/huashijie/util/tracker.py new file mode 100644 index 0000000..3ad0993 --- /dev/null +++ b/huashijie/util/tracker.py @@ -0,0 +1,206 @@ +import copy +from dataclasses import dataclass +import re +import json +import time +from typing import Any, Dict, Optional, Union + +import requests + + +@dataclass +class ProjectMeta: + identifier: str + slug: str + icon: str + deadline: str +@dataclass +class ProjectStatus: + public: bool + paused: bool +@dataclass +class ProjectClient: + version: str + claim_task_delay: float + """ 客户端在 claim_task 之后,多久之后才能再次 claim_task (软限制)""" +@dataclass +class ProjectMongodb: + db_name: str + item_collection: str + queue_collection: str + custom_doc_id_name: str + """ TODO: 未来弃用 """ +@dataclass +class Project: + meta: ProjectMeta + status: ProjectStatus + client: ProjectClient + mongodb: ProjectMongodb + + def __init__(self, meta: dict, status: dict, client: dict, mongodb: dict): + self.meta = ProjectMeta(**meta) + self.status = ProjectStatus(**status) + self.client = ProjectClient(**client) + self.mongodb = ProjectMongodb(**mongodb) + + +TRACKER_NODES = [ + "https://0.tracker.saveweb.org/", + "https://1.tracker.saveweb.org/", + "https://2.tracker.saveweb.org/", + "https://3.tracker.saveweb.org/", +] + +TEST_TRACKER_NODES = [ + "http://localhost:8080/", +] + +class Tracker: + API_BASE = TRACKER_NODES[0] + # API_BASE = TEST_TRACKER_NODES[0] + API_VERSION = "v1" + client_version: str + project_id: str + """ [^a-zA-Z0-9_\\-] """ + archivist: str + """ [^a-zA-Z0-9_\\-] """ + session: requests.Session + project_id: str + __project: Project + __project_last_fetched: float = 0 + + __last_task_claimed_at: float = 0 + + def _is_safe_string(self, s: str): + r = re.compile(r"[^a-zA-Z0-9_\\-]") + return not r.search(s) + + def __init__(self, project_id: str, client_version: str, archivist: str, session: requests.Session): + assert self._is_safe_string(project_id) and self._is_safe_string(archivist), "[^a-zA-Z0-9_\\-]" + self.project_id = project_id + self.client_version = client_version + self.archivist = archivist + self.session = session + + assert self.project.client.version == self.client_version, "client_version mismatch" + + print(f"[tracker] Hello, {self.archivist}!") + print(f"[tracker] Project: {self.project}") + + @property + def project(self): + """ + return: Project, deep copy. + return __project cache if it's not expired (60s) + """ + if time.time() - self.__project_last_fetched > 60: + self.__project = self.fetch_project() + self.__project_last_fetched = time.time() + return copy.deepcopy(self.__project) + + def fetch_project(self): + """ + return: Project, deep copy + also refresh __project cache + """ + assert isinstance(self.session, (requests.Session)) + print("[client->tracker] fetch_project...") + r = self.session.post(self.API_BASE + self.API_VERSION + '/project/' + self.project_id) + r.raise_for_status() + proj = Project(**r.json()) + self.__project = copy.deepcopy(proj) + self.__project_last_fetched = time.time() + print("[client<-tracker] project fetched.") + return proj + + def get_projects(self): + assert isinstance(self.session, (requests.Session)) + print("[client->tracker] get_projects") + r = self.session.post(self.API_BASE + self.API_VERSION + '/projects') + r.raise_for_status() + print("[client<-tracker] get_projects. OK") + return [Project(**p) for p in r.json()] + + + def claim_task(self, with_delay: bool = True): + assert isinstance(self.session, (requests.Session)) + if with_delay: + if sleep_need := self.project.client.claim_task_delay - (time.time() - self.__last_task_claimed_at): + if sleep_need > 0: + print(f"[tracker] slow down you {sleep_need:.2f}s, Qos: {self.project.client.claim_task_delay}") + time.sleep(sleep_need) + elif sleep_need < 0: + print(f"[tracker] you are {sleep_need:.2f}s late, Qos: {self.project.client.claim_task_delay}") + print("[client->tracker] claim_task") + start = time.time() + r = self.session.post(f'{self.API_BASE}{self.API_VERSION}/project/{self.project_id}/{self.client_version}/{self.archivist}/claim_task') + self.__last_task_claimed_at = time.time() + if r.status_code == 404: + print(f'[client<-tracker] claim_task. (time cost: {time.time() - start:.2f}s):', r.text) + return None # No tasks available + if r.status_code == 200: + r_json = r.json() + print(f'[client<-tracker] claim_task. OK (time cost: {time.time() - start:.2f}s):', r_json) + return r_json + raise Exception(r.text) + + def update_task(self, task_id: Union[str, int], status: str)->Dict[str, Any]: + """ + task_id: 必须明确传入的是 int 还是 str + status: 任务状态 + """ + assert isinstance(self.session, (requests.Session)) + assert isinstance(task_id, (str, int)) + assert isinstance(status, str) + + print(f"[client->tracker] update_task task({task_id}) to status({status})") + r = self.session.post( + f'{self.API_BASE}{self.API_VERSION}/project/{self.project_id}/{self.client_version}/{self.archivist}/update_task/{task_id}', + data={ + 'status': status, + 'task_id_type': 'int' if isinstance(task_id, int) else 'str' + }) + if r.status_code == 200: + r_json = r.json() + print(f'[client<-tracker] update_task task({task_id}). OK:', r_json) + return r_json + raise Exception(r.text) + + def insert_item(self, item_id: Union[str, int], item_status: Optional[Union[str, int]] = None, payload: Optional[dict] = None)->Dict[str, Any]: + """ + item_id: 必须明确传入的是 int 还是 str + item_status: item 状态,而不是 task 状态。可用于标记一些被删除、被隐藏的 item 之类的。就不用添加一堆错误响应到 payload 里了。 + payload: 可以传入任意的可转为 ext-json 的对象 (包括 None) + """ + assert isinstance(self.session, (requests.Session)) + # item_id_type + if isinstance(item_id, int): + item_id_type = 'int' + elif isinstance(item_id, str): + item_id_type = 'str' + else: + raise ValueError("item_id must be int or str") + + if item_status is None: + status_type = "None" + elif isinstance(item_status, int): + status_type = "int" + elif isinstance(item_status, str): + status_type = "str" + else: + raise ValueError("status must be int, str or None") + payload_json_str = json.dumps(payload, ensure_ascii=False, separators=(',', ':')) + print(f"[client->tracker] insert_item item({item_id}), len(payload)={len(payload_json_str)}") + r = self.session.post( + f'{self.API_BASE}{self.API_VERSION}/project/{self.project_id}/{self.client_version}/{self.archivist}/insert_item/{item_id}', + data={ + 'item_id_type': item_id_type, + 'item_status': item_status, + 'item_status_type': status_type, + 'payload': payload_json_str + }) + if r.status_code == 200: + r_json = r.json() + print(f'[client<-tracker] insert_item item({item_id}). OK:', r_json) + return r_json + raise Exception(r.text) diff --git a/huashijie/util/unique_str.py b/huashijie/util/unique_str.py new file mode 100644 index 0000000..c57b724 --- /dev/null +++ b/huashijie/util/unique_str.py @@ -0,0 +1,18 @@ +class uniquestr(str): + + _lower = None + + def __hash__(self): + return id(self) + + def __eq__(self, other): + return self is other + + def lower(self): + if self._lower is None: + lower = str.lower(self) + if str.__eq__(lower, self): + self._lower = self + else: + self._lower = uniquestr(lower) + return self._lower diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..cd9c100 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,204 @@ +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. + +[[package]] +name = "bson" +version = "0.5.10" +description = "BSON codec for Python" +optional = false +python-versions = "*" +files = [ + {file = "bson-0.5.10.tar.gz", hash = "sha256:d6511b2ab051139a9123c184de1a04227262173ad593429d21e443d6462d6590"}, +] + +[package.dependencies] +python-dateutil = ">=2.4.0" +six = ">=1.9.0" + +[[package]] +name = "certifi" +version = "2024.2.2" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "idna" +version = "3.7" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "urllib3" +version = "2.2.1" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.9" +content-hash = "17d70c3e5f4343b38290e2cdd06c4ba5f548093a297eb095bc2502adbd3919ff" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..078001d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "huashijie" +version = "1.0.0" +description = "" +authors = ["yzqzss "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.9" +requests = "^2.31.0" +bson = "^0.5.10" + +[tool.poetry.scripts] +huashijie_work = "huashijie.huashijie_work:main" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api"