├── MANIFEST.in ├── setup.py ├── pyproject.toml ├── LICENSE ├── README.md └── nonebot_plugin_leetcode2 ├── template └── template.html ├── get_problem_data.py ├── get_user_data.py └── __init__.py /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include nonebot_plugin_leetcode2/template/template.html -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | setuptools.setup( 4 | name='nonebot_plugin_leetcode2', 5 | version='1.1.3', 6 | author='Nranphy', 7 | author_email='3102002900@qq.com', 8 | url='https://github.com/Nranphy/nonebot_plugin_leetcode2', 9 | description="基于nonebot2的leetcode查询插件。", 10 | long_description=u'一个基于nonebot2的leetcode查询插件,可以查询用户和题目,包含每日一题和随机一题,并可以每日定时发送题目。', 11 | packages=setuptools.find_packages(), 12 | install_requires=[ 13 | "httpx", 14 | "nonebot-plugin-htmlrender", 15 | "nonebot-plugin-apscheduler" 16 | ], 17 | ) -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "nonebot_plugin_leetcode2" 3 | version = "1.1.3" 4 | description = "基于nonebot2的leetcode查询插件。" 5 | authors = ["Nranphy <3102002900@qq.com>"] 6 | license = "MIT" 7 | readme = "README.md" 8 | homepage = "https://github.com/Nranphy/nonebot_plugin_leetcode2" 9 | repository = "https://github.com/Nranphy/nonebot_plugin_leetcode2" 10 | include = [ 11 | "LICENSE", 12 | ] 13 | 14 | [tool.poetry.dependencies] 15 | python = ">=3.7.3" 16 | nonebot2 = ">=2.0.0-beta.2" 17 | nonebot-adapter-onebot = ">=2.0.0-beta.1" 18 | nonebot-plugin-apscheduler = ">=0.1.2" 19 | httpx = ">=0.20.0" 20 | nonebot-plugin-htmlrender = ">=0.2.0.1" 21 | 22 | 23 | [tool.poetry.dev-dependencies] 24 | 25 | [build-system] 26 | requires = ["poetry-core>=1.0.0"] 27 | build-backend = "poetry.core.masonry.api" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nonebot_plugin_leetcode2 2 | 基于nonebot2的leetcode查询插件。 3 | 4 | ## 目前已实现功能 5 | - [x] **对指令`/每日一题`,`/lc`,`/leetcode`回复,发送今天的每日一题。** 6 | 7 | - [x] **可搜索leetcode题目,指令`/lc搜索 XXXXX`,`/lc查找 XXXXX`,`/leetcode搜索 XXXXX`,将以关键词“XXXXX”进行leetcode搜索,发送搜索到的第一道题。** 8 | 9 | - [x] **随机一题,指令`/lc随机`,`/lc随机一题`,`/leetcode随机`将请求leetcode随机一题,发送请求到的任意题目。** 10 | 11 | - [x] **查询用户信息`/lc查询 XXXXX`,`/lc查询用户 XXXXX`,`/leetcode查询 XXXXX`,可查询用户基本信息,XXXXX为用户ID(不能用用户名)。** 12 | 13 | - [x] **加入计划任务** 每日在指定时间向指定群和好友发送当天的每日一题 14 | 15 | ## 使用方法 16 | 17 | 1.在机器人plugins目录下进行git clone 18 | 19 | 2.使用`nb plugin install nonebot_plugin_leetcode2` 20 | 21 | 3.使用`pip install nonebot_plugin_leetcode2`,并修改插件加载。 22 | 23 | ## 注意事项 24 | 25 | 若有需要使用本插件计划任务相关功能,请在.env.\*文件中加入以下设置: 26 | ``` 27 | LEETCODE_QQ_FRIENDS=[3102002900] 28 | LEETCODE_QQ_GROUPS=[805324289] 29 | LEETCODE_INFORM_TIME=[{"HOUR":20,"MINUTE":1},{"HOUR":20,"MINUTE":10},{"HOUR":0,"MINUTE":1}] 30 | ``` 31 | 其中`LEETCODE_QQ_FRIENDS`是欲定期发送题目的好友QQ,`LEETCODE_QQ_GROUPS`是定期发送题目的群聊群号,`LEETCODE_INFORM_TIME`是定时的时间。这和另一个leetcode插件的配置项是相同的。 32 | 33 | 当然,不添加配置项也可正常使用其他功能。感谢@j1g5awi佬的检查与提醒。 34 | 35 | 另外,由于使用到nonebot-plugin-apscheduler插件,请安排插件导入顺序以免发生错误。 -------------------------------------------------------------------------------- /nonebot_plugin_leetcode2/template/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Leetcode 8 | 65 | 66 | 67 | 68 |
69 |

70 | 【title】 71 |

72 | 【content】 73 |
74 | 75 | 76 | -------------------------------------------------------------------------------- /nonebot_plugin_leetcode2/get_problem_data.py: -------------------------------------------------------------------------------- 1 | import httpx 2 | import json 3 | from pathlib import Path 4 | from nonebot.log import logger 5 | 6 | 7 | 8 | def get_random_title() -> str: 9 | '''请求随机题目''' 10 | try: 11 | get_random_data = httpx.post("https://leetcode-cn.com/graphql", json={ 12 | "query": "query problemsetRandomFilteredQuestion($categorySlug: String!, $filters: QuestionListFilterInput) { problemsetRandomFilteredQuestion(categorySlug: $categorySlug, filters: $filters)}", 13 | "variables": { 14 | "categorySlug": "", 15 | "filters": {} 16 | } 17 | }) 18 | random_data = json.loads(get_random_data.text) 19 | titleSlug = random_data["data"]["problemsetRandomFilteredQuestion"] 20 | return titleSlug 21 | except Exception as e: 22 | logger.error("[LC查询] 获取随机题目标题时出错。",e) 23 | raise e 24 | 25 | 26 | def get_today_title() -> str: 27 | '''获取今日的每日一题标题''' 28 | try: 29 | get_today_data = httpx.post("https://leetcode-cn.com/graphql", json={ 30 | "query":"query questionOfToday {todayRecord { date question {frontendQuestionId: questionFrontendId difficulty titleSlug } } } ", 31 | "variables":{} 32 | }) 33 | today_data = json.loads(get_today_data.text) 34 | titleSlug = today_data["data"]["todayRecord"][0]["question"]["titleSlug"] 35 | return titleSlug 36 | except Exception as e: 37 | logger.error("[LC查询] 获取每日一题标题时出错。",e) 38 | raise e 39 | 40 | 41 | def get_search_title(keyword) -> str: 42 | '''调用查询接口进行查询,返回首个查询结果题目标题''' 43 | try: 44 | get_search_data = httpx.post("https://leetcode-cn.com/graphql", json={ 45 | "query": "query problemsetQuestionList($categorySlug: String, $limit: Int, $skip: Int, $filters: QuestionListFilterInput) { problemsetQuestionList( categorySlug: $categorySlug limit: $limit skip: $skip filters: $filters ) { hasMore total questions { acRate difficulty freqBar frontendQuestionId isFavor paidOnly solutionNum status title titleCn titleSlug topicTags { name nameTranslated id slug } extra { hasVideoSolution topCompanyTags { imgUrl slug numSubscribed } } } }} ", 46 | "variables": { 47 | "categorySlug": "", 48 | "skip": 0, 49 | "limit": 1, 50 | "filters": { 51 | "searchKeywords": keyword 52 | } 53 | } 54 | }) 55 | search_data = json.loads(get_search_data.text) 56 | question_list = search_data["data"]["problemsetQuestionList"]["questions"] 57 | if question_list: 58 | titleSlug = question_list[0]["titleSlug"] 59 | else: 60 | titleSlug = "" 61 | return titleSlug 62 | except Exception as e: 63 | logger.error("[LC查询] 获取搜索标题时出错。",e) 64 | raise e 65 | 66 | 67 | def get_sub_problem_data(titleSlug) -> list: 68 | '''获取某一已知名称的题目内容''' 69 | try: 70 | with open(Path(__file__).parent / "template" / "template.html", "r", encoding="UTF-8") as f: 71 | html_template = f.read() 72 | except Exception as e: 73 | logger.error("[LC查询] 载入HTML模板时发生错误。",e) 74 | raise e 75 | try: 76 | get_problem_data = httpx.post("https://leetcode-cn.com/graphql", json={ 77 | "operationName": "questionData", 78 | "variables": { 79 | "titleSlug": titleSlug }, 80 | "query": "query questionData($titleSlug: String!) { question(titleSlug: $titleSlug) { questionFrontendId title titleSlug translatedTitle translatedContent difficulty } } " 81 | }) 82 | problem_data = json.loads(get_problem_data.text) 83 | problem_data = problem_data["data"]["question"] 84 | #题目信息(题号+题目译名) 85 | problem_title = problem_data.get("questionFrontendId")+"."+problem_data.get("translatedTitle") 86 | #题目难度(英语单词) 87 | problem_difficulty = "题目难度:"+problem_data.get("difficulty") 88 | #题目内容(用html输出) 89 | problem_content:str = problem_data.get("translatedContent") 90 | problem_content = html_template.replace("【content】",(problem_content.replace('\\"', '"'))).replace("【title】", problem_title) 91 | #题目链接 92 | problem_link = "本题链接:"+f"https://leetcode-cn.com/problems/{titleSlug}/" 93 | return [problem_title, problem_difficulty, problem_content, problem_link] 94 | except Exception as e: 95 | logger.error("[LC查询] 获取已知题目的内容时出错。",e) 96 | raise e -------------------------------------------------------------------------------- /nonebot_plugin_leetcode2/get_user_data.py: -------------------------------------------------------------------------------- 1 | import httpx 2 | import json 3 | from nonebot.log import logger 4 | 5 | 6 | 7 | def get_user_public_profile(userSlug): 8 | '''获取用户公开信息''' 9 | try: 10 | get_data = httpx.post("https://leetcode-cn.com/graphql", json={ 11 | "operationName": "userPublicProfile", 12 | "variables": { 13 | "userSlug": userSlug 14 | }, 15 | "query": "query userPublicProfile($userSlug: String!) { userProfilePublicProfile(userSlug: $userSlug) { username haveFollowed siteRanking profile { userSlug realName aboutMe userAvatar location gender websites skillTags contestCount asciiCode medals { name year month category __typename } ranking { rating ranking currentLocalRanking currentGlobalRanking currentRating ratingProgress totalLocalUsers totalGlobalUsers __typename } skillSet { langLevels { langName langVerboseName level __typename } topics { slug name translatedName __typename } topicAreaScores { score topicArea { name slug __typename } __typename } __typename } socialAccounts { provider profileUrl __typename } __typename } educationRecordList { unverifiedOrganizationName __typename } occupationRecordList { unverifiedOrganizationName jobTitle __typename } submissionProgress { totalSubmissions waSubmissions acSubmissions reSubmissions otherSubmissions acTotal questionTotal __typename } __typename }}" 16 | }) 17 | user_public_data = json.loads(get_data.text) 18 | return user_public_data 19 | except Exception as e: 20 | logger.error("[LC查询] 获取用户公开信息时出错。",e) 21 | raise e 22 | 23 | 24 | 25 | def get_user_question_progress(userSlug): 26 | '''获取用户已通过题目''' 27 | try: 28 | get_data = httpx.post("https://leetcode-cn.com/graphql", json={ 29 | "operationName": "userQuestionProgress", 30 | "variables": { 31 | "userSlug": userSlug 32 | }, 33 | "query": "query userQuestionProgress($userSlug: String!) { userProfileUserQuestionProgress(userSlug: $userSlug) { numAcceptedQuestions { difficulty count __typename } numFailedQuestions { difficulty count __typename } numUntouchedQuestions { difficulty count __typename } __typename }}" 34 | }) 35 | user_question_progress = json.loads(get_data.text) 36 | return user_question_progress 37 | except Exception as e: 38 | logger.error("[LC查询] 获取用户已通过题目时出错。",e) 39 | raise e 40 | 41 | 42 | 43 | def get_user_solution_count(userSlug): 44 | '''获取用户已发布题解数''' 45 | try: 46 | get_data = httpx.post("https://leetcode-cn.com/graphql", json={ 47 | "operationName": "columnsUserSolutionCount", 48 | "variables": { 49 | "userSlug": userSlug 50 | }, 51 | "query": "query columnsUserSolutionCount($userSlug: String!) {\n columnsUserSolutionCount(userSlug: $userSlug)\n}\n" 52 | }) 53 | user_solution_count = json.loads(get_data.text) 54 | return user_solution_count 55 | except Exception as e: 56 | logger.error("[LC查询] 获取用户已发布题解数时出错。",e) 57 | raise e 58 | 59 | 60 | 61 | def get_user_profile_articles(userSlug): 62 | '''获取用户最新题解题目''' 63 | try: 64 | get_data = httpx.post("https://leetcode-cn.com/graphql", json={ 65 | "operationName": "profileArticles", 66 | "variables": { 67 | "userSlug": userSlug, 68 | "skip": 0, 69 | "first": 15 70 | }, 71 | "query": "query profileArticles($userSlug: String!, $skip: Int, $first: Int) {\n solutionArticles(userSlug: $userSlug, skip: $skip, first: $first) {\n edges {\n node {\n title\n slug\n question {\n title\n titleSlug\n translatedTitle\n questionFrontendId\n __typename\n }\n upvoteCount\n topic {\n commentCount\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n" 72 | }) 73 | user_profile_articles = json.loads(get_data.text) 74 | return user_profile_articles 75 | except Exception as e: 76 | logger.error("[LC查询] 获取用户最新题解时出错。",e) 77 | raise e 78 | 79 | 80 | 81 | def get_user_community_achievement(userSlug): 82 | '''获取用户声望信息''' 83 | try: 84 | get_data = httpx.post("https://leetcode-cn.com/graphql", json={ 85 | "operationName": "profileCommunityAchievement", 86 | "variables": { 87 | "userSlug": userSlug, 88 | "size": 3 89 | }, 90 | "query": "query profileCommunityAchievement($size: Int!, $userSlug: String!) {\n profileCommunityAchievement(size: $size, userSlug: $userSlug) {\n date\n voteCount\n viewCount\n favoriteCount\n __typename\n }\n}\n" 91 | }) 92 | user_community_achievement = json.loads(get_data.text) 93 | return user_community_achievement 94 | except Exception as e: 95 | logger.error("[LC查询] 获取用户声望信息时出错。",e) 96 | raise e 97 | 98 | 99 | 100 | def get_user_question_submitstats(userSlug): 101 | '''获取用户题目提交统计''' 102 | try: 103 | get_data = httpx.post("https://leetcode-cn.com/graphql", json={ 104 | "operationName": "userQuestionSubmitStats", 105 | "variables": { 106 | "userSlug": userSlug 107 | }, 108 | "query": "query userQuestionSubmitStats($userSlug: String!) {\n userProfileUserQuestionSubmitStats(userSlug: $userSlug) {\n acSubmissionNum {\n difficulty\n count\n __typename\n }\n totalSubmissionNum {\n difficulty\n count\n __typename\n }\n __typename\n }\n}\n" 109 | }) 110 | user_question_submitstat = json.loads(get_data.text) 111 | return user_question_submitstat 112 | except Exception as e: 113 | logger.error("[LC查询] 获取用户题目提交统计时出错。",e) 114 | raise e 115 | 116 | 117 | 118 | def get_user_medals(userSlug): 119 | '''获取用户勋章''' 120 | try: 121 | get_data = httpx.post("https://leetcode-cn.com/graphql", json={ 122 | "operationName": "userMedals", 123 | "variables": { 124 | "userSlug": userSlug 125 | }, 126 | "query": "query userMedals($userSlug: String!) {\n userProfileUserMedals(userSlug: $userSlug) {\n ...medalNodeFragment\n __typename\n }\n userProfileUserLevelMedal(userSlug: $userSlug) {\n current {\n ...medalNodeFragment\n __typename\n }\n next {\n ...medalNodeFragment\n __typename\n }\n __typename\n }\n userProfileUserNextMedal(userSlug: $userSlug) {\n ...medalNodeFragment\n __typename\n }\n}\n\nfragment medalNodeFragment on MedalNodeV2 {\n name\n obtainDate\n category\n config {\n icon\n iconGif\n iconGifBackground\n __typename\n }\n progress\n id\n year\n month\n __typename\n}\n" 127 | }) 128 | user_medals = json.loads(get_data.text) 129 | return user_medals 130 | except Exception as e: 131 | logger.error("[LC查询] 获取用户勋章信息时出错。",e) 132 | raise e -------------------------------------------------------------------------------- /nonebot_plugin_leetcode2/__init__.py: -------------------------------------------------------------------------------- 1 | from nonebot import on_command, require, get_bot, get_driver 2 | from nonebot.log import logger 3 | from nonebot.typing import T_State 4 | from nonebot.adapters.onebot.v11 import Bot, Event, MessageSegment 5 | 6 | from nonebot_plugin_htmlrender import html_to_pic 7 | 8 | from .get_problem_data import * 9 | from .get_user_data import * 10 | 11 | 12 | 13 | request_today = on_command("lc每日",aliases={"lc","leetcode"},priority = 10,block = True) 14 | 15 | request_search = on_command("lc查找",aliases={"lc搜索","leetcode搜索"},priority = 10,block = True) 16 | 17 | request_random = on_command("lc随机",aliases={"lc随机一题","leetcode随机"},priority = 10,block = True) 18 | 19 | request_user = on_command("lc查询",aliases={"lc查询用户","leetcode查询"},priority = 10,block = True) 20 | 21 | 22 | try: 23 | scheduler = require("nonebot_plugin_apscheduler").scheduler 24 | except Exception as e: 25 | logger.error("[LC查询] require定时插件时出错,请检查插件加载顺序。") 26 | 27 | 28 | 29 | 30 | #查询每日一题 31 | @request_today.handle() 32 | async def send_today_problem(bot: Bot,event:Event): 33 | try: 34 | today_title = get_today_title() 35 | logger.info(f"[LC查询] 获取今日题目成功,题目为{today_title}.") 36 | today_data = get_sub_problem_data(today_title) 37 | logger.info("[LC查询] 获取题目内容成功。") 38 | logger.debug(f"[LC查询] 题目{today_data[0]}的难度为{today_data[1]}") 39 | except Exception as e: 40 | logger.error("[LC查询] 无法连接至leetcode,请检查网络和网络代理状态。") 41 | await request_today.finish("连接到leetcode失败...呜呜呜...\n请稍后再试!!") 42 | 43 | pic = await html_to_pic(today_data[2], viewport={"width": 840, "height": 400}) 44 | await request_today.send("获取今日每日一题成功~加油哦ww\n"+"\n".join(today_data[:2])+MessageSegment.image(pic)+f"\n{today_data[3]}") 45 | 46 | 47 | 48 | 49 | 50 | 51 | #搜索题目 52 | @request_search.handle() 53 | async def parse(bot: Bot, event: Event, state: T_State): 54 | temp = str(event.get_message()).split() 55 | try: 56 | state["keyword"] = temp[1] 57 | except Exception: 58 | pass 59 | 60 | 61 | @request_search.got("keyword",prompt="请输出要在leetcode查找的内容哦~\n可为题号、题目、题干内容哒") 62 | async def send_today_problem(bot: Bot,event:Event, state: T_State): 63 | try: 64 | search_title = get_search_title(state["keyword"]) 65 | if search_title: 66 | logger.info(f"[LC查询] 成功搜索到关键字题目,只取第一条,题目为{search_title}.") 67 | else: 68 | logger.info("[LC查询] 搜索成功,但并无相关题目。") 69 | request_search.finish("未搜索到相关题目!!\n要不...换个关键字再搜索一下吧~可为题号、题目、题干内容哒") 70 | 71 | data = get_sub_problem_data(search_title) 72 | logger.info("[LC查询] 获取题目内容成功。") 73 | logger.debug(f"[LC查询] 题目{data[0]}的难度为{data[1]}") 74 | except Exception as e: 75 | logger.error("[LC查询] 无法连接至leetcode,请检查网络和网络代理状态。") 76 | await request_search.finish("连接到leetcode失败...呜呜呜...\n请稍后再试!!") 77 | 78 | pic = await html_to_pic(data[2], viewport={"width": 840, "height": 400}) 79 | await request_search.send("搜索成功~只发送了最相关题目哦ww\n"+"\n".join(data[:2])+MessageSegment.image(pic)+f"\n{data[3]}") 80 | 81 | 82 | 83 | 84 | 85 | 86 | #随机一题 87 | @request_random.handle() 88 | async def send_random_problem(bot: Bot,event:Event): 89 | try: 90 | random_title = get_random_title() 91 | logger.info(f"[LC查询] 获取随机一题题目成功,题目为{random_title}.") 92 | random_data = get_sub_problem_data(random_title) 93 | logger.info("[LC查询] 获取题目内容成功。") 94 | logger.debug(f"[LC查询] 题目{random_data[0]}的难度为{random_data[1]}") 95 | except Exception as e: 96 | logger.error("[LC查询] 无法连接至leetcode,请检查网络和网络代理状态。") 97 | await request_random.finish("连接到leetcode失败...呜呜呜...\n请稍后再试!!") 98 | 99 | pic = await html_to_pic(random_data[2], viewport={"width": 840, "height": 400}) 100 | await request_random.send("成功获取随机一题~加油哦ww\n"+"\n".join(random_data[:2])+MessageSegment.image(pic)+f"\n{random_data[3]}") 101 | 102 | 103 | 104 | 105 | 106 | 107 | #查询用户信息 108 | @request_user.handle() 109 | async def parse(bot: Bot, event: Event, state: T_State): 110 | temp = str(event.get_message()).split() 111 | if temp[1]: 112 | state["userSlug"] = temp[1] 113 | 114 | 115 | @request_user.got("userSlug",prompt="请输出要在leetcode查询的用户哦~\n请写入用户ID,而非用户昵称哦~") 116 | async def send_user_data(bot: Bot,event:Event, state: T_State): 117 | try: 118 | #详细的返回json信息请查阅json/文件夹内的文本,或者参见get_user_data.py 119 | user_public_profile = get_user_public_profile(state["userSlug"]) 120 | user_question_progress = get_user_question_progress(state["userSlug"]) 121 | user_solution_count = get_user_solution_count(state["userSlug"]) 122 | user_profile_articles = get_user_profile_articles(state["userSlug"]) 123 | user_community_achievement = get_user_community_achievement(state["userSlug"]) 124 | user_question_submitstats = get_user_question_submitstats(state["userSlug"]) 125 | user_medals = get_user_medals(state["userSlug"]) 126 | except Exception as e: 127 | logger.error("[LC查询] 无法连接至leetcode,请检查网络和网络代理状态。") 128 | await request_user.finish("连接到leetcode失败...呜呜呜...\n请稍后再试!!") 129 | try: 130 | userSlug = state["userSlug"] 131 | realName = user_public_profile["data"]["userProfilePublicProfile"]["profile"]["realName"] 132 | userAvatar = httpx.get(user_public_profile["data"]["userProfilePublicProfile"]["profile"]["userAvatar"]) 133 | totalSubmissions = user_public_profile["data"]["userProfilePublicProfile"]["submissionProgress"]["totalSubmissions"] 134 | waSubmissions = user_public_profile["data"]["userProfilePublicProfile"]["submissionProgress"]["waSubmissions"] 135 | acSubmissions = user_public_profile["data"]["userProfilePublicProfile"]["submissionProgress"]["acSubmissions"] 136 | reSubmissions = user_public_profile["data"]["userProfilePublicProfile"]["submissionProgress"]["reSubmissions"] 137 | otherSubmissions = user_public_profile["data"]["userProfilePublicProfile"]["submissionProgress"]["otherSubmissions"] 138 | acTotal = user_public_profile["data"]["userProfilePublicProfile"]["submissionProgress"]["acTotal"] 139 | logger.debug("[LC查询] user_public_profile数据解析完成") 140 | 141 | if user_community_achievement["data"]["profileCommunityAchievement"]: 142 | voteCount = user_community_achievement["data"]["profileCommunityAchievement"][0]["voteCount"] 143 | viewCount = user_community_achievement["data"]["profileCommunityAchievement"][0]["viewCount"] 144 | favoriteCount = user_community_achievement["data"]["profileCommunityAchievement"][0]["favoriteCount"] 145 | else: 146 | voteCount,viewCount,favoriteCount = 0,0,0 147 | logger.debug("[LC查询] user_community_achievement数据解析完成") 148 | 149 | numAcceptedQuestions_easy = user_question_progress["data"]["userProfileUserQuestionProgress"]["numAcceptedQuestions"][0]["count"] 150 | numAcceptedQuestions_medium = user_question_progress["data"]["userProfileUserQuestionProgress"]["numAcceptedQuestions"][1]["count"] 151 | numAcceptedQuestions_difficulty = user_question_progress["data"]["userProfileUserQuestionProgress"]["numAcceptedQuestions"][2]["count"] 152 | numFailedQuestions_easy = user_question_progress["data"]["userProfileUserQuestionProgress"]["numFailedQuestions"][0]["count"] 153 | numFailedQuestions_medium = user_question_progress["data"]["userProfileUserQuestionProgress"]["numFailedQuestions"][1]["count"] 154 | numFailedQuestions_difficulty = user_question_progress["data"]["userProfileUserQuestionProgress"]["numFailedQuestions"][2]["count"] 155 | numUntouchedQuestions_easy = user_question_progress["data"]["userProfileUserQuestionProgress"]["numUntouchedQuestions"][0]["count"] 156 | numUntouchedQuestions_medium = user_question_progress["data"]["userProfileUserQuestionProgress"]["numUntouchedQuestions"][1]["count"] 157 | numUntouchedQuestions_difficulty = user_question_progress["data"]["userProfileUserQuestionProgress"]["numUntouchedQuestions"][2]["count"] 158 | logger.debug("[LC查询] user_question_progress数据解析完成") 159 | 160 | columnsUserSolutionCount = user_solution_count["data"]["columnsUserSolutionCount"] 161 | logger.debug("[LC查询] user_solution_count数据解析完成") 162 | 163 | acSubmissionNum_easy = user_question_submitstats["data"]["userProfileUserQuestionSubmitStats"]["acSubmissionNum"][0]["count"] 164 | acSubmissionNum_medium = user_question_submitstats["data"]["userProfileUserQuestionSubmitStats"]["acSubmissionNum"][1]["count"] 165 | acSubmissionNum_hard = user_question_submitstats["data"]["userProfileUserQuestionSubmitStats"]["acSubmissionNum"][2]["count"] 166 | logger.debug("[LC查询] user_question_submitstats数据解析完成") 167 | 168 | if user_medals["data"]["userProfileUserMedals"]: 169 | latest_madal_name = user_medals["data"]["userProfileUserMedals"][0]["name"] 170 | latest_madal_date = user_medals["data"]["userProfileUserMedals"][0]["obtainDate"] 171 | latest_madal = f"【最近勋章】 勋章名:{latest_madal_name} |获得时间:{latest_madal_date}\n" 172 | else: 173 | latest_madal = "" 174 | logger.debug("[LC查询] user_medals数据解析完成") 175 | 176 | if user_profile_articles["data"]["solutionArticles"]["edges"]: 177 | latest_article_title = f'【最近题解】:{user_profile_articles["data"]["solutionArticles"]["edges"][0]["node"]["title"]}\n' 178 | else: 179 | latest_article_title = "" 180 | logger.debug("[LC查询] user_profile_articles数据解析完成") 181 | 182 | 183 | except Exception as e: 184 | await request_user.finish("解析用户信息出错×\n用户ID错误或不存在,请输入用户ID而非用户昵称哦~") 185 | 186 | await request_user.send(\ 187 | "用户查询数据成功~\n"+\ 188 | MessageSegment.image(userAvatar.read())+\ 189 | f"用户名:{realName}({userSlug})\n"+\ 190 | "========\n"+\ 191 | f"【已解决问题】 EASY:{numAcceptedQuestions_easy} |MEDIUM:{numAcceptedQuestions_medium} |DIFFICULTY:{numAcceptedQuestions_difficulty}\n"+\ 192 | f"【未答出问题】 EASY:{numFailedQuestions_easy} |MEDIUM:{numFailedQuestions_medium} |DIFFICULTY:{numFailedQuestions_difficulty}\n"+\ 193 | f"【未接触问题】 EASY:{numUntouchedQuestions_easy} |MEDIUM:{numUntouchedQuestions_medium} |DIFFICULTY:{numUntouchedQuestions_difficulty}\n"+\ 194 | f"【历史提交】 提交总数:{totalSubmissions} |错误提交数:{waSubmissions} |正确提交数:{acSubmissions} |重新提交数:{reSubmissions} |其他提交数:{otherSubmissions} |AC总数:{acTotal}\n"+\ 195 | f"【提交通过数】 EASY:{acSubmissionNum_easy} |MEDIUM:{acSubmissionNum_medium} |DIFFICULTY:{acSubmissionNum_hard}\n"+\ 196 | "========\n" 197 | f"【成就贡献】 阅读总数:{viewCount} |获得点赞:{voteCount} |获得收藏:{favoriteCount} |发布题解:{columnsUserSolutionCount}\n"+\ 198 | latest_madal+latest_article_title+\ 199 | f"用户主页:https://leetcode-cn.com/u/{userSlug}/") 200 | 201 | 202 | 203 | 204 | 205 | #定时发送 206 | 207 | time_list = get_driver().config.leetcode_inform_time if hasattr(get_driver().config, "leetcode_inform_time") else list() 208 | 209 | async def send_leetcode_everyday(): 210 | qq_list = get_bot().config.leetcode_qq_friends if hasattr(get_driver().config, "leetcode_qq_friends") else list() 211 | group_list = get_bot().config.leetcode_qq_groups if hasattr(get_driver().config, "leetcode_qq_groups") else list() 212 | try: 213 | today_title = get_today_title() 214 | logger.info(f"[LC查询] 获取今日题目成功,题目为{today_title}.") 215 | today_data = get_sub_problem_data(today_title) 216 | logger.info("[LC查询] 获取题目内容成功。") 217 | logger.debug(f"[LC查询] 题目{today_data[0]}的难度为{today_data[1]}") 218 | except Exception as e: 219 | logger.error("[LC查询] 无法连接至leetcode,请检查网络和网络代理状态。") 220 | pass 221 | pic = await html_to_pic(today_data[2], viewport={"width": 840, "height": 400}) 222 | try: 223 | for qq in qq_list: 224 | await get_bot().call_api("send_private_msg",user_id = qq ,message = "获取今日每日一题成功~加油哦ww\n"+"\n".join(today_data[:2])+MessageSegment.image(pic)+f"\n{today_data[3]}") 225 | for group in group_list: 226 | await get_bot().call_api("send_group_msg",group_id = group ,message = "获取今日每日一题成功~加油哦ww\n"+"\n".join(today_data[:2])+MessageSegment.image(pic)+f"\n{today_data[3]}") 227 | except TypeError: 228 | logger.error("[LC查询] 插件定时发送相关设置有误,请检查.env.*文件。") 229 | 230 | 231 | 232 | 233 | 234 | try: 235 | for index, time in enumerate(time_list): 236 | scheduler.add_job(send_leetcode_everyday, "cron", hour=time["HOUR"], minute=time["MINUTE"], id=f"leetcode_{str(index)}") 237 | logger.info(f"[LC查询] 新建计划任务成功!! id:leetcode_{index},时间为:{time}.") 238 | except TypeError: 239 | logger.error("[LC查询] 插件定时发送相关设置有误,请检查.env.*文件。") --------------------------------------------------------------------------------