This commit is contained in:
yzqzss 2024-04-21 20:49:25 +08:00
parent 5f6ef17d7d
commit a99ace395c
10 changed files with 701 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.vscode
__pycache__

52
huashijie/hsj_api.py Normal file
View File

@ -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': '由于作者隐私设置,您没有权限查看此作品'}

127
huashijie/huashijie_work.py Normal file
View File

@ -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()

View File

@ -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()

15
huashijie/util/device.py Normal file
View File

@ -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"
]

40
huashijie/util/task.py Normal file
View File

@ -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

206
huashijie/util/tracker.py Normal file
View File

@ -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)

View File

@ -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

204
poetry.lock generated Normal file
View File

@ -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"

18
pyproject.toml Normal file
View File

@ -0,0 +1,18 @@
[tool.poetry]
name = "huashijie"
version = "1.0.0"
description = ""
authors = ["yzqzss <yzqzss@yandex.com>"]
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"