diff --git a/README.md b/README.md
index 729f690..05e0535 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@
- 本项目为[青年大学习提交](https://github.com/ZM25XC/nonebot_plugin_auto_teenstudy) `Web UI`版
- 本项目基于[nonebot2](https://github.com/nonebot/nonebot2)和[go-cqhttp](https://github.com/Mrs4s/go-cqhttp),使用本插件前请先阅读以上两个项目的使用文档
- **启动插件之后,一定要登录后台在推送列表中添加需要开启大学习功能的群聊**
+- **本项目无法在国外IP环境下使用,如有开启代理,请关闭或添加代理规则**
- 需要抓包的地区,绑定后尽量别进官方公众号,避免token或cookie刷新导致无法提交
- 本项目需要部署在公网可访问的容器中,并开放端口(nonebot2配置的port),否则大部分功能将出现异常
- 欢迎加入[QQ群](https://jq.qq.com/?_wv=1027&k=NGFEwXyS),交流讨论。
@@ -36,6 +37,7 @@
|青春湖北|支持|无需抓包|
|江西共青团|支持|无需抓包|
|安徽共青团|支持|无需抓包|
+|广东共青团|支持|无需抓包|
|青春上海|支持|微信扫码绑定|
|青春浙江|支持|微信扫码绑定|
|江苏共青团|支持|需要自行抓包|
@@ -58,7 +60,6 @@
|海南共青团|待开发||
|津彩青春|待开发||
|青春黔言|待开发||
-|广东共青团|待开发||
|青春柳州|待开发||
|辽宁共青团|待开发||
|宁夏共青团|待开发||
@@ -159,13 +160,20 @@
## 更新日志
-### 2023/05/06
+### 2023/05/11
+
+- 增加广东地区,无需抓包[#13](https://github.com/ZM25XC/TeenStudy/issues/13),感谢[@neal240](https://github.com/neal240)提供账号测试
+
+
+
+2023/05/06
- 增加吉林地区,需要自行抓包
- 修复超管更改登录密码后用原密码能继续登录问题
- 添加二维码转链接开关,需要自行在后台配置页面打开
- 调整部分依赖
+
2023/04/12
diff --git a/TeenStudy/utils/dxx.py b/TeenStudy/utils/dxx.py
index ab463c7..f139165 100644
--- a/TeenStudy/utils/dxx.py
+++ b/TeenStudy/utils/dxx.py
@@ -3,6 +3,7 @@
import re
import secrets
import time
+import urllib.parse
from anti_useragent import UserAgent
from httpx import AsyncClient
@@ -905,3 +906,172 @@ async def jilin(user_id: int) -> dict:
"status": 500,
"msg": f"提交失败,{e}"
}
+
+
+async def guangdong(user_id: int) -> dict:
+ """
+ 广东共青团
+ :param user_id:用户ID
+ :return:
+ """
+ result = await User.filter(user_id=user_id).values()
+ if not result:
+ return {
+ "status": 500,
+ "msg": "用户数据不存在!"
+ }
+ else:
+ dxx_id = result[0]['dxx_id']
+ token = result[0]["token"]
+ answer = await Answer.all().order_by("time").values()
+ try:
+ study_headers = {
+ 'Host': 'youthstudy.12355.net',
+ 'Connection': 'keep-alive',
+ 'X-Litemall-Token': token,
+ 'X-Litemall-IdentiFication': 'young',
+ 'User-Agent': 'MicroMessenger',
+ 'Accept': '*/*',
+ 'Origin': 'https://youthstudy.12355.net',
+ 'X-Requested-With': 'com.tencent.mm',
+ 'Sec-Fetch-Site': 'same-origin',
+ 'Sec-Fetch-Mode': 'cors',
+ 'Sec-Fetch-Dest': 'empty',
+ 'Referer': 'https://youthstudy.12355.net/h5/',
+ 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
+ }
+ new_study_url = "https://youthstudy.12355.net/saomah5/api/young/chapter/new"
+ async with AsyncClient(headers=study_headers, timeout=30, max_redirects=5) as client:
+ study_response = await client.get(url=new_study_url)
+ study_response.encoding=study_response.charset_encoding
+ if study_response.json()["errno"] == 0:
+ chapterId = study_response.json().get('data').get('entity').get('id')
+ title = study_response.json().get('data').get('entity').get('name').replace('“青年大学习”', "").strip()
+ commit_url = "https://youthstudy.12355.net/saomah5/api/young/course/chapter/saveHistory"
+ async with AsyncClient(headers=study_headers, timeout=30, max_redirects=5) as client:
+ commit_response = await client.post(url=commit_url, data={
+ "chapterId": chapterId
+ })
+ if commit_response.json()["errno"] == 0:
+ await User.filter(user_id=user_id).update(
+ token=token,
+ commit_time=time.time(),
+ catalogue=title
+ )
+ await commit(user_id=user_id, catalogue=title, status=True)
+ return {
+ "status": 0,
+ "catalogue": title,
+ "msg": "提交成功!"
+ }
+ else:
+ await commit(user_id=user_id, catalogue=answer[-1]["catalogue"], status=False)
+ return {
+ "status": 500,
+ "msg": "提交失败!"
+ }
+ else:
+ token_headers = {
+ 'Host': 'tuanapi.12355.net',
+ 'Connection': 'keep-alive',
+ 'Accept': 'application/json, text/javascript, */*; q=0.01',
+ 'Origin': 'https://tuan.12355.net',
+ 'User-Agent': 'MicroMessenger',
+ 'X-Requested-With': 'com.tencent.mm',
+ 'Sec-Fetch-Site': 'same-site',
+ 'Sec-Fetch-Mode': 'cors',
+ 'Referer': 'https://tuan.12355.net/wechat/view/YouthLearning/page.html',
+ 'Accept-Encoding': 'gzip, deflate',
+ 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
+ }
+ ger_param_url = f"https://tuanapi.12355.net/questionnaire/getYouthLearningUrl?mid={dxx_id}"
+ async with AsyncClient(headers=token_headers, timeout=30, max_redirects=5) as client:
+ param_response = await client.get(url=ger_param_url)
+ if param_response.json()["status"] == 200:
+ content = param_response.json()["youthLearningUrl"].split("=")[-1]
+ token_url = "https://youthstudy.12355.net/apih5/api/user/get"
+ token_headers = {
+ 'Host': 'youthstudy.12355.net',
+ 'Connection': 'keep-alive',
+ 'Content-Length': '134',
+ 'Origin': 'https://youthstudy.12355.net',
+ 'X-Litemall-Token': '',
+ 'X-Litemall-IdentiFication': 'young',
+ 'User-Agent': 'MicroMessenger',
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Accept': '*/*',
+ 'X-Requested-With': 'com.tencent.mm',
+ 'Sec-Fetch-Site': 'same-origin',
+ 'Sec-Fetch-Mode': 'cors',
+ 'Referer': 'https://youthstudy.12355.net/h5/',
+ 'Accept-Encoding': 'gzip, deflate',
+ 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7'
+ }
+ async with AsyncClient(headers=token_headers, timeout=30, max_redirects=5) as client:
+ token_response = await client.post(url=token_url, data="sign="+urllib.parse.quote(content))
+ if token_response.json()["errno"] == 0:
+ token = token_response.json()['data']['entity']['token']
+ study_headers = {
+ 'Host': 'youthstudy.12355.net',
+ 'Connection': 'keep-alive',
+ 'X-Litemall-Token': token,
+ 'X-Litemall-IdentiFication': 'young',
+ 'User-Agent': 'MicroMessenger',
+ 'Accept': '*/*',
+ 'Origin': 'https://youthstudy.12355.net',
+ 'X-Requested-With': 'com.tencent.mm',
+ 'Sec-Fetch-Site': 'same-origin',
+ 'Sec-Fetch-Mode': 'cors',
+ 'Sec-Fetch-Dest': 'empty',
+ 'Referer': 'https://youthstudy.12355.net/h5/',
+ 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
+ }
+ new_study_url = "https://youthstudy.12355.net/saomah5/api/young/chapter/new"
+ async with AsyncClient(headers=study_headers, timeout=30, max_redirects=5) as client:
+ study_response = await client.get(url=new_study_url)
+ if study_response.json()["errno"] == 0:
+ chapterId = study_response.json().get('data').get('entity').get('id')
+ title = study_response.json().get('data').get('entity').get('name').replace(
+ '"青年大学习”', "").strip()
+ commit_url = "https://youthstudy.12355.net/saomah5/api/young/course/chapter/saveHistory"
+ async with AsyncClient(headers=study_headers, timeout=30, max_redirects=5) as client:
+ commit_response = await client.post(url=commit_url, data={
+ "chapterId": chapterId
+ })
+ if commit_response.json()["errno"] == 0:
+ await User.filter(user_id=user_id).update(
+ token=token,
+ commit_time=time.time(),
+ catalogue=title
+ )
+ await commit(user_id=user_id, catalogue=title, status=True)
+ return {
+ "status": 0,
+ "catalogue": title,
+ "msg": "提交成功!"
+ }
+ else:
+ await commit(user_id=user_id, catalogue=answer[-1]["catalogue"], status=False)
+ return {
+ "status": 500,
+ "msg": "提交失败!"
+ }
+ else:
+ await commit(user_id=user_id, catalogue=answer[-1]["catalogue"], status=False)
+ return {
+ "status": 500,
+ "msg": "提交失败,token获取失效!"
+ }
+ else:
+ await commit(user_id=user_id, catalogue=answer[-1]["catalogue"], status=False)
+ return {
+ "status": 500,
+ "msg": "提交失败,token获取失效!"
+ }
+ except Exception as e:
+ logger.error(e)
+ await commit(user_id=user_id, catalogue=answer[-1]["catalogue"], status=False)
+ return {
+ "status": 500,
+ "msg": "提交失败!"
+ }
diff --git a/TeenStudy/utils/utils.py b/TeenStudy/utils/utils.py
index 324a687..72d7009 100644
--- a/TeenStudy/utils/utils.py
+++ b/TeenStudy/utils/utils.py
@@ -170,6 +170,15 @@ class UserModel(BaseModel):
"status": True,
"catalogue": None
},
+ {
+ "area": "广东",
+ "host": "tuanapi.12355.net",
+ "referer": None,
+ "origin": "https://tuan.12355.net",
+ "url": "https://youthstudy.12355.net/saomah5/api/young/chapter/new",
+ "status": True,
+ "catalogue": None
+ },
]
RESOURCE = [
{
@@ -506,6 +515,8 @@ async def distribute_area(user_id: int, area: str) -> dict:
return await dxx.chongqing(user_id=user_id)
elif area == "吉林":
return await dxx.jilin(user_id=user_id)
+ elif area == "广东":
+ return await dxx.guangdong(user_id=user_id)
else:
return {
"status": 404,
@@ -531,6 +542,8 @@ async def distribute_area_url(province: str, user_id: int, group_id: int) -> dic
province = "chongqing"
elif province == "吉林":
province = "jilin"
+ elif province == "广东":
+ province="guangdong"
data = f"http://{config['DXX_IP']}:{config['DXX_PORT']}/TeenStudy/api/{province}?user_id={user_id}&group_id={group_id}"
img = qrcode.make(data=data)
buf = BytesIO()
diff --git a/TeenStudy/web/api/add.py b/TeenStudy/web/api/add.py
index 47df102..2e96d23 100644
--- a/TeenStudy/web/api/add.py
+++ b/TeenStudy/web/api/add.py
@@ -1,6 +1,7 @@
import json
import re
import time
+import urllib.parse
from typing import Optional
from fastapi import APIRouter
@@ -8,7 +9,7 @@
from httpx import AsyncClient
from ..pages.add import hubei_page, jiangxi_page, jiangsu_page, anhui_page, sichuan_page, shandong_page, \
- chongqing_page, jilin_page
+ chongqing_page, jilin_page, guangdong_page
from ..utils.add import write_to_database
from ...models.accuont import User, AddUser
from ...models.dxx import JiangXi
@@ -651,7 +652,7 @@ async def jilin_add(data: dict) -> JSONResponse:
user_id = data["user_id"]
if await User.filter(user_id=user_id).count():
return JSONResponse({
- "status": 0,
+ "status": 500,
"msg": "添加失败!,用户信息存在!"
})
else:
@@ -718,3 +719,98 @@ async def jilin(user_id: int, group_id: int):
return RedirectResponse(
url="/TeenStudy/login"
)
+
+
+@route.post("/guangdong/add", response_class=HTMLResponse)
+async def guangdong_add(data: dict) -> JSONResponse:
+ user_id = data["user_id"]
+ if await User.filter(user_id=user_id).count():
+ return JSONResponse({
+ "status": 500,
+ "msg": "添加失败!,用户信息存在!"
+ })
+ else:
+ try:
+ url = data["url"]
+ dxx_id = re.findall(r"memberId=(.*?)&showMemberAdditionNames", url)[0]
+ token_headers = {
+ 'Host': 'tuanapi.12355.net',
+ 'Connection': 'keep-alive',
+ 'Accept': 'application/json, text/javascript, */*; q=0.01',
+ 'Origin': 'https://tuan.12355.net',
+ 'User-Agent': 'MicroMessenger',
+ 'X-Requested-With': 'com.tencent.mm',
+ 'Sec-Fetch-Site': 'same-site',
+ 'Sec-Fetch-Mode': 'cors',
+ 'Referer': 'https://tuan.12355.net/wechat/view/YouthLearning/page.html',
+ 'Accept-Encoding': 'gzip, deflate',
+ 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
+ }
+ ger_param_url = f"https://tuanapi.12355.net/questionnaire/getYouthLearningUrl?mid={dxx_id}"
+ async with AsyncClient(headers=token_headers, timeout=30, max_redirects=5) as client:
+ param_response = await client.get(url=ger_param_url)
+ if param_response.json()["status"] == 200:
+ content = param_response.json()["youthLearningUrl"].split("=")[-1]
+ token_url = "https://youthstudy.12355.net/apih5/api/user/get"
+ token_headers = {
+ 'Host': 'youthstudy.12355.net',
+ 'Connection': 'keep-alive',
+ 'Origin': 'https://youthstudy.12355.net',
+ 'X-Litemall-Token': '',
+ 'X-Litemall-IdentiFication': 'young',
+ 'User-Agent': 'MicroMessenger',
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Accept': '*/*',
+ 'X-Requested-With': 'com.tencent.mm',
+ 'Sec-Fetch-Site': 'same-origin',
+ 'Sec-Fetch-Mode': 'cors',
+ 'Referer': 'https://youthstudy.12355.net/h5/',
+ 'Accept-Encoding': 'gzip, deflate',
+ 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7'
+ }
+ async with AsyncClient(headers=token_headers, timeout=30, max_redirects=5) as client:
+ token_response = await client.post(url=token_url, data="sign="+urllib.parse.quote(content))
+ if token_response.json()["errno"] == 0:
+ token = token_response.json()['data']['entity']['token']
+ name = token_response.json()['data']['entity']['nickName']
+ organization_id = token_response.json()['data']['entity']['organizeId']
+ data["name"] = name
+ data["organization_id"] = organization_id
+ data["dxx_id"] = dxx_id
+ data["token"]=token
+ data.pop("url")
+ status = await write_to_database(data=data)
+ if status:
+ return JSONResponse(
+ {
+ "status": 0,
+ "msg": "添加成功!"
+ }
+ )
+ else:
+ return JSONResponse({
+ "status": 500,
+ "msg": "添加失败!"
+ })
+ else:
+ return JSONResponse({"status": 500, "msg": "添加失败!"})
+ else:
+ return JSONResponse({"status": 500, "msg": "添加失败!"})
+ except Exception as e:
+ return JSONResponse({
+ "status": 500,
+ "msg": f"添加失败,{e}"
+ })
+
+
+@route.get("/guangdong", response_class=HTMLResponse)
+async def guangdong(user_id: int, group_id: int):
+ result = await AddUser.filter(user_id=user_id, group_id=group_id, status="未通过").count()
+ if result:
+ return guangdong_page.render(
+ site_title='广东共青团 | TeenStudy',
+ site_icon="https://i.328888.xyz/2023/02/23/xIh5k.png"
+ )
+ return RedirectResponse(
+ url="/TeenStudy/login"
+ )
diff --git a/TeenStudy/web/pages/add.py b/TeenStudy/web/pages/add.py
index 14c7f6b..968e258 100644
--- a/TeenStudy/web/pages/add.py
+++ b/TeenStudy/web/pages/add.py
@@ -842,3 +842,99 @@
)
jilin_page = Page(title='添加大学习', body=[logo, Divider(), jilin_table, footer])
+
+guangdong_table = Form(
+ title="广东共青团",
+ mode=DisplayModeEnum.horizontal,
+ api="post:/TeenStudy/api/guangdong/add",
+ redirect="/TeenStudy/login",
+ body=[
+ Alert(level=LevelEnum.info,
+ className='white-space-pre-wrap',
+ body=(
+ "链接获取方式:\n12355青春之声公众号\n智慧团建-认证资料-生成电子团员证,点击最下方生成按钮。\n在团员证页面复制链接 应为:https://tuan.12355.net/wechat/view/information/member_certification_generated.html?memberId=xxxxxx&showMemberAdditionNames=&showMemberRewardIds=&isShowAllFee=true \n其中xxxxxx即为mid")),
+ InputText(
+ label="用户ID",
+ description="用户ID,为用户QQ号,无需填写",
+ name="user_id",
+ value="${user_id}",
+ disabled=True
+ ),
+ InputText(
+ label="通知群ID",
+ description="通知群号,无需填写",
+ name="group_id",
+ value="${group_id}",
+ disabled=True
+ ),
+ InputText(
+ label="地区",
+ description="所处省份",
+ name="area",
+ value="广东",
+ disabled=True
+ ),
+ InputText(
+ label="登录密码",
+ type='input-password',
+ description="可不填,默认为用户ID",
+ name="password",
+ inline=False,
+ required=False,
+ value="",
+ clearable=True,
+ maxLength=16
+ ),
+ InputText(
+ label="姓名",
+ description="您的姓名",
+ name="name",
+ inline=False,
+ required=True,
+ value="",
+ clearable=True,
+ maxLength=8
+ ),
+ InputText(
+ label="url",
+ description="链接格式:https://tuan.12355.net/wechat/view/information/member_certification_generated.html?memberId=xxxxxx&showMemberAdditionNames=&showMemberRewardIds=&isShowAllFee=true",
+ name="url",
+ inline=False,
+ required=True,
+ value="",
+ clearable=True,
+ maxLength=512
+ ),
+ InputText(
+ label="学校",
+ description="你就读的高校",
+ name="university",
+ inline=False,
+ required=True,
+ value="",
+ clearable=True,
+ maxLength=24
+ ),
+ InputText(
+ label="学院",
+ description="学院名称",
+ name="college",
+ inline=False,
+ required=True,
+ value="",
+ clearable=True,
+ maxLength=32
+ ),
+ InputText(
+ label="团支部",
+ description="团支部|班级,没有可不填",
+ name="organization",
+ inline=False,
+ required=False,
+ value="",
+ clearable=True,
+ maxLength=32
+ )]
+)
+
+guangdong_page = Page(title='添加大学习', body=[logo, Divider(), guangdong_table, footer])
diff --git a/TeenStudy/web/pages/admin.py b/TeenStudy/web/pages/admin.py
index dc3bee0..1b68d1d 100644
--- a/TeenStudy/web/pages/admin.py
+++ b/TeenStudy/web/pages/admin.py
@@ -1394,6 +1394,115 @@
]
)
+"""广东地区添加用户"""
+guangdong_table = Form(
+ title="广东共青团",
+ mode=DisplayModeEnum.horizontal,
+ api="post:/TeenStudy/api/guangdong/add",
+ redirect="/TeenStudy/login",
+ body=[
+ Alert(level=LevelEnum.info,
+ className='white-space-pre-wrap',
+ body=(
+ "链接获取方式:\n12355青春之声公众号\n智慧团建-认证资料-生成电子团员证,点击最下方生成按钮。\n在团员证页面复制链接 应为:https://tuan.12355.net/wechat/view/information/member_certification_generated.html?memberId=xxxxxx&showMemberAdditionNames=&showMemberRewardIds=&isShowAllFee=true \n其中xxxxxx即为mid")),
+ Select(
+ label="群聊",
+ name="group_id",
+ description="需要添加的群组",
+ checkAll=False,
+ source="get:/TeenStudy/api/get_group_list",
+ value='',
+ multiple=False,
+ required=True,
+ searchable=True,
+ joinValues=False,
+ extractValue=True,
+ statistics=True,
+ ),
+ Select(
+ label="用户ID",
+ name="user_id",
+ description="需要添加的用户ID",
+ checkAll=False,
+ source="get:/TeenStudy/api/get_member_list?group_id=${group_id}",
+ value='',
+ multiple=False,
+ required=True,
+ searchable=True,
+ joinValues=False,
+ extractValue=True,
+ statistics=True,
+ hiddenOn="${group_id==''?true:false}"
+ ),
+ InputText(
+ label="地区",
+ description="所处省份",
+ name="area",
+ value="广东",
+ disabled=True
+ ),
+ InputText(
+ label="登录密码",
+ type='input-password',
+ description="可不填,默认为用户ID",
+ name="password",
+ inline=False,
+ required=False,
+ value="",
+ clearable=True,
+ maxLength=16
+ ),
+ InputText(
+ label="姓名",
+ description="您的姓名",
+ name="name",
+ inline=False,
+ required=True,
+ value="",
+ clearable=True,
+ maxLength=8
+ ),
+ InputText(
+ label="url",
+ description="链接格式:https://tuan.12355.net/wechat/view/information/member_certification_generated.html?memberId=xxxxxx&showMemberAdditionNames=&showMemberRewardIds=&isShowAllFee=true",
+ name="url",
+ inline=False,
+ required=True,
+ value="",
+ clearable=True,
+ maxLength=512
+ ),
+ InputText(
+ label="学校",
+ description="你就读的高校",
+ name="university",
+ inline=False,
+ required=True,
+ value="",
+ clearable=True,
+ maxLength=24
+ ),
+ InputText(
+ label="学院",
+ description="学院名称",
+ name="college",
+ inline=False,
+ required=True,
+ value="",
+ clearable=True,
+ maxLength=32
+ ),
+ InputText(
+ label="团支部",
+ description="团支部|班级,没有可不填",
+ name="organization",
+ inline=False,
+ required=False,
+ value="",
+ clearable=True,
+ maxLength=32
+ )]
+)
"""推送群聊模板"""
push_table = CRUD(mode='table',
title='',
@@ -1475,6 +1584,8 @@
schema=Page(title='重庆共青团', body=[chongqing_table]))
jilin_page = PageSchema(url='/add/jilin', icon='fa fa-pen-to-square', label='吉青飞扬',
schema=Page(title='吉青飞扬', body=[jilin_table]))
+guangdong_page = PageSchema(url='/add/guangdong', icon='fa fa-pen-to-square', label='广东共青团',
+ schema=Page(title='广东共青团', body=[guangdong_table]))
admin_app = App(brandName='TeenStudy',
logo='https://i.328888.xyz/2023/02/23/xIh5k.png',
header=header,
@@ -1483,7 +1594,7 @@
admin_page,
PageSchema(icon='fa fa-circle-user', label='成员管理',
children=[list_page, hubei_page, jiangxi_page, jiangsu_page, anhui_page,
- sichuan_page, shandong_page, chongqing_page, jilin_page]),
+ sichuan_page, shandong_page, chongqing_page, jilin_page,guangdong_page]),
PageSchema(url="/notice", label='推送列表', icon='fa fa-bell',
schema=Page(title='', body=[push_table])),
PageSchema(url="/request", label='申请记录', icon='fa fa-circle-info',
diff --git a/pyproject.toml b/pyproject.toml
index 1397bf3..2c38d3f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
-name = "teenstudy"
-version = "0.1.7"
+name = "TeenStudy"
+version = "0.1.8"
description = "基于nonebot2异步框架的青年大学自动提交插件基于nonebot2的青年大学习自动提交插件,用于自动完成大学习,在后台留下记录,返回完成截图"
authors = ["ZM25XC "]
license="MIT"