├── Almanac
├── __init__.py
├── demo.png
├── README.md
├── Almanac.py
└── get_data.py
├── poetry
├── __init__.py
├── test.py
└── Poety.py
├── CetsHelper
├── __init__.py
├── src.zip
├── demo.png
├── demo2.png
├── voice
│ ├── hour.mp3
│ ├── idle.mp3
│ ├── spark.mp3
│ └── hello my name is Tony.mp3
├── README.md
├── 发音.py
├── 单词生成.py
├── CetsHelper.py
└── data
│ └── 2023-11-26.json
├── RandomWord
├── __init__.py
├── demo.png
├── README.md
├── test.py
└── RandomWord.py
├── SearchIP
├── __init__.py
├── demo.png
├── requirements.txt
├── README.md
├── IPInfo.py
├── SearchIP.py
└── IPHistory.py
├── TopHub163
├── __init__.py
├── demo.png
├── README.md
└── Tophub163.py
├── CTFCalendar
├── __init__.py
├── demo.png
├── README.md
├── CTFCalendar.py
└── GetCalendar.py
├── SearchDomain
├── __init__.py
├── demo.png
├── requirements.txt
├── README.md
├── CanRegister.py
├── IsExtranet.py
├── SearchDomain.py
├── DomainInfo.py
└── DomainDNS.py
├── 已废弃
├── SearchICP
│ ├── __init__.py
│ ├── demo.png
│ ├── README.md
│ ├── test.py
│ ├── test2.py
│ ├── test3.py
│ └── SearchICP.py
└── WorkCalendar
│ ├── __init__.py
│ ├── demo.png
│ ├── README.md
│ └── WorkCalendar.py
├── FishCalendar
├── __init__.py
├── README.md
├── demo.png
└── FishCalendar.py
├── WindowsHostInfo
├── __init__.py
├── demo.png
├── README.md
├── WindowsHostInfo.py
└── systemfuc.py
├── PerpetualCalendar
├── __init__.py
├── demo.png
├── README.md
├── test.py
└── PerpetualCalendar.py
├── TodaysQuotationste
├── __init__.py
├── demo.png
├── README.md
└── TodaysQuotationste.py
├── CurrentAffairs
├── __init__.py
├── 1.jpg
├── demo.png
├── README.md
├── test.py
└── CurrentAffairs.py
├── VulnerabilityIntelligence
├── __init__.py
├── SearchCVE.py
├── requirements.txt
├── demo.png
├── README.md
├── VulnerabilityIntelligence.py
└── SearchCNNVD.py
├── README.md
├── .gitignore
└── LICENSE
/Almanac/__init__.py:
--------------------------------------------------------------------------------
1 | from .Almanac import *
--------------------------------------------------------------------------------
/poetry/__init__.py:
--------------------------------------------------------------------------------
1 | from .Poety import *
2 |
--------------------------------------------------------------------------------
/CetsHelper/__init__.py:
--------------------------------------------------------------------------------
1 | from .CetsHelper import *
--------------------------------------------------------------------------------
/RandomWord/__init__.py:
--------------------------------------------------------------------------------
1 | from .RandomWord import *
--------------------------------------------------------------------------------
/SearchIP/__init__.py:
--------------------------------------------------------------------------------
1 | from .SearchIP import *
2 |
--------------------------------------------------------------------------------
/TopHub163/__init__.py:
--------------------------------------------------------------------------------
1 | from .Tophub163 import *
--------------------------------------------------------------------------------
/CTFCalendar/__init__.py:
--------------------------------------------------------------------------------
1 | from .CTFCalendar import *
--------------------------------------------------------------------------------
/SearchDomain/__init__.py:
--------------------------------------------------------------------------------
1 | from .SearchDomain import *
--------------------------------------------------------------------------------
/已废弃/SearchICP/__init__.py:
--------------------------------------------------------------------------------
1 | from .SearchICP import *
--------------------------------------------------------------------------------
/FishCalendar/__init__.py:
--------------------------------------------------------------------------------
1 | from .FishCalendar import *
2 |
--------------------------------------------------------------------------------
/WindowsHostInfo/__init__.py:
--------------------------------------------------------------------------------
1 | from .WindowsHostInfo import *
--------------------------------------------------------------------------------
/PerpetualCalendar/__init__.py:
--------------------------------------------------------------------------------
1 | from .PerpetualCalendar import *
--------------------------------------------------------------------------------
/已废弃/WorkCalendar/__init__.py:
--------------------------------------------------------------------------------
1 | from .WorkCalendar import *
2 |
--------------------------------------------------------------------------------
/TodaysQuotationste/__init__.py:
--------------------------------------------------------------------------------
1 | from .TodaysQuotationste import *
2 |
--------------------------------------------------------------------------------
/CurrentAffairs/__init__.py:
--------------------------------------------------------------------------------
1 | from .CurrentAffairs import *
2 |
3 |
4 |
--------------------------------------------------------------------------------
/VulnerabilityIntelligence/__init__.py:
--------------------------------------------------------------------------------
1 | from .VulnerabilityIntelligence import *
--------------------------------------------------------------------------------
/Almanac/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/Almanac/demo.png
--------------------------------------------------------------------------------
/CetsHelper/src.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/CetsHelper/src.zip
--------------------------------------------------------------------------------
/SearchIP/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/SearchIP/demo.png
--------------------------------------------------------------------------------
/TopHub163/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/TopHub163/demo.png
--------------------------------------------------------------------------------
/CTFCalendar/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/CTFCalendar/demo.png
--------------------------------------------------------------------------------
/CetsHelper/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/CetsHelper/demo.png
--------------------------------------------------------------------------------
/CetsHelper/demo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/CetsHelper/demo2.png
--------------------------------------------------------------------------------
/CurrentAffairs/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/CurrentAffairs/1.jpg
--------------------------------------------------------------------------------
/RandomWord/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/RandomWord/demo.png
--------------------------------------------------------------------------------
/VulnerabilityIntelligence/SearchCVE.py:
--------------------------------------------------------------------------------
1 | """
2 | https://www.tenable.com/cve/search?q=&sort=&page=1
3 | """
--------------------------------------------------------------------------------
/VulnerabilityIntelligence/requirements.txt:
--------------------------------------------------------------------------------
1 | my-fake-useragent==0.2.1
2 | requests==2.28.2
3 | openpyxl==3.1.2
--------------------------------------------------------------------------------
/CurrentAffairs/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/CurrentAffairs/demo.png
--------------------------------------------------------------------------------
/FishCalendar/README.md:
--------------------------------------------------------------------------------
1 | # 摸鱼日历
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
--------------------------------------------------------------------------------
/FishCalendar/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/FishCalendar/demo.png
--------------------------------------------------------------------------------
/SearchDomain/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/SearchDomain/demo.png
--------------------------------------------------------------------------------
/已废弃/SearchICP/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/已废弃/SearchICP/demo.png
--------------------------------------------------------------------------------
/CetsHelper/voice/hour.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/CetsHelper/voice/hour.mp3
--------------------------------------------------------------------------------
/CetsHelper/voice/idle.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/CetsHelper/voice/idle.mp3
--------------------------------------------------------------------------------
/SearchIP/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/SearchIP/requirements.txt
--------------------------------------------------------------------------------
/WindowsHostInfo/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/WindowsHostInfo/demo.png
--------------------------------------------------------------------------------
/已废弃/WorkCalendar/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/已废弃/WorkCalendar/demo.png
--------------------------------------------------------------------------------
/CetsHelper/voice/spark.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/CetsHelper/voice/spark.mp3
--------------------------------------------------------------------------------
/PerpetualCalendar/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/PerpetualCalendar/demo.png
--------------------------------------------------------------------------------
/TodaysQuotationste/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/TodaysQuotationste/demo.png
--------------------------------------------------------------------------------
/已废弃/WorkCalendar/README.md:
--------------------------------------------------------------------------------
1 | # 打工人日历(已弃用)
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
--------------------------------------------------------------------------------
/SearchDomain/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/SearchDomain/requirements.txt
--------------------------------------------------------------------------------
/VulnerabilityIntelligence/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/VulnerabilityIntelligence/demo.png
--------------------------------------------------------------------------------
/CetsHelper/voice/hello my name is Tony.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XcNgg/chatgpt-on-wechat-plugins/HEAD/CetsHelper/voice/hello my name is Tony.mp3
--------------------------------------------------------------------------------
/RandomWord/README.md:
--------------------------------------------------------------------------------
1 | # 随机语录
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | ## 版本更新
9 |
10 | - V1.0:实现基本语录功能
11 |
--------------------------------------------------------------------------------
/PerpetualCalendar/README.md:
--------------------------------------------------------------------------------
1 | # 万年历
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | ## 版本更新
9 |
10 | - V1.0:实现万年历功能
11 |
--------------------------------------------------------------------------------
/CurrentAffairs/README.md:
--------------------------------------------------------------------------------
1 | # 时政要闻
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | ### 版本说明
9 |
10 | - V1.0:实现基本时政要闻功能
11 |
--------------------------------------------------------------------------------
/CTFCalendar/README.md:
--------------------------------------------------------------------------------
1 | # CTF夺旗赛日历
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | ### 版本说明
9 |
10 | - V1.0:实现夺旗赛CTF日历基本功能
11 |
--------------------------------------------------------------------------------
/WindowsHostInfo/README.md:
--------------------------------------------------------------------------------
1 | # Windows主机巡检
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | ### 更新说明
9 |
10 | - V1.0 :实现基本主机巡检功能
11 |
--------------------------------------------------------------------------------
/TodaysQuotationste/README.md:
--------------------------------------------------------------------------------
1 | # 今日语录
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | ## 版本更新
9 |
10 | - V1.0:实现基本语录功能
11 | - V1.1:修复英文bug
12 | -
13 |
--------------------------------------------------------------------------------
/已废弃/SearchICP/README.md:
--------------------------------------------------------------------------------
1 | # ICP备案查询
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | ### 版本更新
9 |
10 | - V1.0:域名基本信息、地区、机构查询
11 | - V1.1:域名是否需要翻墙
12 | - V1.2:域名是否可以注册
13 |
--------------------------------------------------------------------------------
/CetsHelper/README.md:
--------------------------------------------------------------------------------
1 | # CETS助手
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | 
9 |
10 | ## 版本更新
11 |
12 | - V1.0:实现每日单词功能,关键词【发音 nice】自动发送单词音频
13 |
--------------------------------------------------------------------------------
/SearchIP/README.md:
--------------------------------------------------------------------------------
1 | # IP所属查询
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | ### 版本更新
9 | - v1.0 实现IP基本信息查询
10 | - V1.1 新增查询IP历史DNS解析记录(默认仅输出前10条,可调整)
11 | - V1.2 修复相关问题,模块拆分
12 | - V1.2.1 改进请求超时问题
--------------------------------------------------------------------------------
/VulnerabilityIntelligence/README.md:
--------------------------------------------------------------------------------
1 | # 漏洞情报查询
2 |
3 | ## 介绍
4 |
5 | chatgpt-on-wechat-plugins插件开发
6 |
7 | 根据漏洞CNNVD、CVE(开发中...)等漏洞编号,查询漏洞信息
8 |
9 | ## 配置
10 |
11 | 
12 |
13 | ### 更新说明
14 |
15 | - V1.0 :实现基本漏洞查询功能
16 |
--------------------------------------------------------------------------------
/Almanac/README.md:
--------------------------------------------------------------------------------
1 | # 万年历
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | - 需要在`config.json`与`config.py` 添加`almanac_key`
9 | - 接口来源https://www.juhe.cn/box/index/id/65
10 |
11 | ## 版本更新
12 |
13 | - V1.0:实现黄历功能
14 |
--------------------------------------------------------------------------------
/CurrentAffairs/test.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | url = "https://v.api.aa1.cn/api/60s-v3/?cc=%E5%9B%BD%E5%86%85%E8%A6%81%E9%97%BB?type=CurrentAffairs.jpg"
4 | response = requests.get(url)
5 |
6 |
7 | with open('1.jpg','wb') as file:
8 | file.write(response.content)
9 |
10 |
--------------------------------------------------------------------------------
/SearchDomain/README.md:
--------------------------------------------------------------------------------
1 | # 域名查询
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | 
7 |
8 | ### 环境安装
9 |
10 | ```cmd
11 | pip install -r requirements.txt
12 | ```
13 |
14 | ### 版本更新
15 |
16 | - V1.0:域名基本信息、地区、机构查询
17 | - V1.1:新增域名是否需要翻墙
18 | - V1.2:新增域名是否可以注册
19 | - V1.3:新增域名解析记录,更名"域名查询"
20 | - V1.4: 模块分割
--------------------------------------------------------------------------------
/TopHub163/README.md:
--------------------------------------------------------------------------------
1 | # 网易热榜查询
2 |
3 | #### 介绍
4 | chatgpt-on-wechat-plugins插件开发
5 |
6 | ## 配置
7 |
8 | 需要在config.json和config.py上新建参数
9 |
10 | ```python
11 | token = conf().get("tophub_token") # 从配置文件中获取 tophub_token
12 | news_type = conf().get("tophub_type") # 从配置文件中获取 tophub_type
13 | ```
14 | 
15 |
16 | ### 更新说明
17 |
18 | - V1.0 :实现基本网易热榜功能
19 | - V1.1:修改关键词,插件更名`TopHub163`
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # chatgpt-on-wechat插件
2 |
3 | 基于 https://github.com/zhayujie/chatgpt-on-wechat
4 |
5 | 都是一些自用的小插件,单一功能,进去看`readme`即可
6 |
7 | 需要哪个把哪个插件拖到`plugins`路径下即可,部分插件需要配置`config.json`
8 |
9 | > gitee:https://gitee.com/XcNGG/chatgpt-on-wechat-plugins
10 | >
11 | > github:https://github.com/XcNgg/chatgpt-on-wechat-plugins
12 |
13 | ## 插件说明
14 |
15 | ### 更新中
16 |
17 | 1. FishCalendar 摸鱼日历
18 | 2. SearchDomain 域名查询
19 | 3. SearchIP ip查询
20 | 4. TodaysQuotationste 每日语录
21 | 5. TopHub163 网易新闻热榜
22 | 6. RandomWord 随机语录
23 | 7. WindowsHostInfo Windows主机状态巡检
24 | 8. PerpetualCalendar万年历
25 | 9. Almanac 黄历
26 | 10. CurrentAffairs 政务要闻
27 | 11. Poetry 随机诗词
28 | 12. CetsHelper CETS单词助手(每日背单词)
29 | 13. CTF日历(数据来源-[ctfhub](https://api.ctfhub.com/User_API/Event/getAllICS))
30 |
31 | ### 已废弃
32 |
33 | 1. WorkCalendar 工作日历(已废弃)
34 | 2. SearchICP 域名查询(已废弃,更新为`SearchDomain 域名查询`)
35 |
--------------------------------------------------------------------------------
/已废弃/SearchICP/test.py:
--------------------------------------------------------------------------------
1 | """
2 | 基本功能 查看域名信息
3 | """
4 | import requests
5 | domain = 'baidu.com'
6 | headers = {
7 | "authority": "api.uutool.cn",
8 | "accept": "application/json, text/javascript, */*; q=0.01",
9 | "accept-language": "zh-CN,zh;q=0.9",
10 | "cache-control": "no-cache",
11 | "origin": "https://uutool.cn",
12 | "pragma": "no-cache",
13 | "referer": "https://uutool.cn/",
14 | "sec-ch-ua": "^\\^Google",
15 | "sec-ch-ua-mobile": "?0",
16 | "sec-ch-ua-platform": "^\\^Windows^^",
17 | "sec-fetch-dest": "empty",
18 | "sec-fetch-mode": "cors",
19 | "sec-fetch-site": "same-site",
20 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
21 | }
22 | url = "https://api.uutool.cn/beian/icp/"
23 | data = {
24 | "domain": domain
25 | }
26 | response = requests.post(url, headers=headers, data=data).json()
27 | print(response)
--------------------------------------------------------------------------------
/CetsHelper/发音.py:
--------------------------------------------------------------------------------
1 | # import requests
2 | #
3 | # # http://dict.youdao.com/dictvoice?type=音频类型&audio=单词
4 | # # 请求方法:get
5 | # # type=0 : 美音
6 | # # type=1 : 英音
7 | # # audio : 单词
8 | #
9 | # def get_voice(word):
10 | # url = "http://dict.youdao.com/dictvoice?type=1&audio=" + word
11 | # response = requests.get(url)
12 | # path = r"./voice/"
13 | # with open(path+word + '.mp3', 'wb') as mp3:
14 | # mp3.write(response.content)
15 | #
16 |
17 |
18 | import json
19 | import os
20 |
21 | # 创建一个空字典来存储所有的单词数据
22 | all_words = []
23 |
24 |
25 | for i in range(ord('A'), ord('Z')+1):
26 | # 读取A到Z的json文件并合并到all_words中
27 | with open(f'src/JSON/{chr(i)}.json','r',encoding='utf-8') as file:
28 | data = json.load(file)
29 | all_words += data
30 |
31 | print(all_words)
32 | # 保存为total.json
33 | with open('src/total.json', 'w') as file:
34 | json.dump(all_words, file, ensure_ascii=False, indent=4)
35 |
36 |
37 |
38 | # 打印合并后的单词总数
39 | print(f"Total words: {len(all_words)}")
40 |
--------------------------------------------------------------------------------
/RandomWord/test.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 |
4 | headers = {
5 | "authority": "api.vvhan.com",
6 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
7 | "accept-language": "zh-CN,zh;q=0.9",
8 | "cache-control": "no-cache",
9 | "pragma": "no-cache",
10 | "sec-ch-ua": "^\\^Google",
11 | "sec-ch-ua-mobile": "?0",
12 | "sec-ch-ua-platform": "^\\^Windows^^",
13 | "sec-fetch-dest": "document",
14 | "sec-fetch-mode": "navigate",
15 | "sec-fetch-site": "none",
16 | "sec-fetch-user": "?1",
17 | "upgrade-insecure-requests": "1",
18 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
19 | }
20 |
21 | url = "https://api.vvhan.com/api/ian"
22 | params = {
23 | "type": "json"
24 | }
25 | response = requests.get(url, headers=headers,params=params)
26 |
27 | print(response.text)
28 | print(response)
--------------------------------------------------------------------------------
/已废弃/SearchICP/test2.py:
--------------------------------------------------------------------------------
1 | """
2 | 查看域名是否被墙
3 | """
4 | import requests
5 |
6 | headers = {
7 | "authority": "api.vvhan.com",
8 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
9 | "accept-language": "zh-CN,zh;q=0.9",
10 | "cache-control": "no-cache",
11 | "pragma": "no-cache",
12 | "sec-ch-ua": "^\\^Google",
13 | "sec-ch-ua-mobile": "?0",
14 | "sec-ch-ua-platform": "^\\^Windows^^",
15 | "sec-fetch-dest": "document",
16 | "sec-fetch-mode": "navigate",
17 | "sec-fetch-site": "none",
18 | "sec-fetch-user": "?1",
19 | "upgrade-insecure-requests": "1",
20 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
21 | }
22 |
23 | url = "https://api.vvhan.com/api/qiang"
24 | params = {
25 | "url": "google.com"
26 | }
27 | response = requests.get(url, headers=headers, params=params)
28 |
29 | print(response.text)
30 | print(response)
--------------------------------------------------------------------------------
/已废弃/SearchICP/test3.py:
--------------------------------------------------------------------------------
1 | """
2 | 查看域名是否可以注册
3 | """
4 | """
5 | 查看域名是否被墙
6 | """
7 | import requests
8 |
9 | headers = {
10 | "authority": "api.vvhan.com",
11 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
12 | "accept-language": "zh-CN,zh;q=0.9",
13 | "cache-control": "no-cache",
14 | "pragma": "no-cache",
15 | "sec-ch-ua": "^\\^Google",
16 | "sec-ch-ua-mobile": "?0",
17 | "sec-ch-ua-platform": "^\\^Windows^^",
18 | "sec-fetch-dest": "document",
19 | "sec-fetch-mode": "navigate",
20 | "sec-fetch-site": "none",
21 | "sec-fetch-user": "?1",
22 | "upgrade-insecure-requests": "1",
23 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
24 | }
25 |
26 | url = "https://api.vvhan.com/api/dm"
27 | params = {
28 | "url": "google.com"
29 | }
30 |
31 | response = requests.get(url=url, headers=headers,params=params).json()
32 |
33 | print(response)
34 | if response.get('success', False):
35 | print(response.get('message'))
--------------------------------------------------------------------------------
/poetry/test.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from my_fake_useragent import UserAgent
3 | import pprint
4 |
5 | def get_data():
6 | """
7 | return
8 | from_who:作者
9 | hitokoto:诗词
10 | _from:诗词名称
11 | """
12 | headers = {
13 | "User-Agent" : UserAgent().random()
14 | }
15 | url = "https://v1.hitokoto.cn/?c=i&encode=json"
16 | response = requests.get(url=url,headers=headers)
17 | result = response.json()
18 | from_who = result.get('from_who',"未知")
19 | hitokoto = result.get('hitokoto',"未知")
20 | _from = result.get('from',"未知")
21 | return from_who,hitokoto,_from
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | if __name__ == '__main__':
30 | from_who,hitokoto,_from = get_data()
31 | """
32 | {'commit_from': 'api',
33 | 'created_at': '1586395379',
34 | 'creator': 'a632079',
35 | 'creator_uid': 1044,
36 | 'from': '放言五首·其五',
37 | 'from_who': '白居易',
38 | 'hitokoto': '松树千年终是朽,槿花一日自为荣。',
39 | 'id': 5761,
40 | 'length': 16,
41 | 'reviewer': 1044,
42 | 'type': 'i',
43 | 'uuid': 'e3854f83-cfb2-496f-803e-873981c4e699'}
44 | """
45 | response = f"{hitokoto} \n --{from_who} ·《{_from}》"
46 | print(response)
--------------------------------------------------------------------------------
/CurrentAffairs/CurrentAffairs.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 | import requests
3 | import plugins
4 | from bridge.context import ContextType
5 | from bridge.reply import Reply, ReplyType
6 | from common.log import logger
7 | from plugins import *
8 |
9 |
10 | @plugins.register(
11 | name="时政要闻",
12 | desire_priority=0,
13 | # namecn="时政要闻",
14 | desc="输入关键词'时政要闻'即可获取今日时政要闻哦-By XcNGG",
15 | version="1.0",
16 | author="XcNGG",
17 | )
18 | class CurrentAffairs(Plugin):
19 | def __init__(self):
20 | super().__init__()
21 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
22 | logger.info("[CurrentAffairs-XcNGG] inited.")
23 |
24 | def on_handle_context(self, e_context: EventContext):
25 | content = e_context["context"].content # 获取事件上下文中的消息内容
26 | if content == "时政要闻": # 如果消息内容为 "摸鱼日历"
27 | url = "https://v.api.aa1.cn/api/60s-v3/?cc=%E5%9B%BD%E5%86%85%E8%A6%81%E9%97%BB?type=CurrentAffairs.jpg"
28 | reply = Reply()
29 | reply.type = ReplyType.IMAGE_URL
30 | reply.content = url
31 |
32 | e_context["reply"] = reply
33 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
34 |
35 |
36 | def get_help_text(self, **kwargs):
37 | help_text = "关键词【时政要闻】By XcNGG"
38 | return help_text
--------------------------------------------------------------------------------
/CetsHelper/单词生成.py:
--------------------------------------------------------------------------------
1 | import json
2 | import random
3 | import os
4 | from datetime import datetime
5 |
6 |
7 |
8 | def get_words():
9 | # 生成新的json文件名
10 | date = datetime.now().strftime('%Y-%m-%d')
11 | new_file_name = f"data/{date}.json"
12 | if not os.path.exists(new_file_name):
13 | # 读取total.json文件
14 | with open('data/total.json', 'r',encoding='utf-8') as f:
15 | data = json.load(f)
16 |
17 | if len(data) >=20:
18 | # 从data中随机选择20个单词
19 | random_words = random.sample(data, 20)
20 | else:
21 | random_words = random.sample(data, len(data))
22 |
23 | # 将随机选择的单词写入新的json文件
24 | with open(new_file_name, 'w',encoding='utf-8') as f:
25 | json.dump(random_words, f)
26 | # 从total.json中删除随机选择的单词
27 | data = [word for word in data if word not in random_words]
28 | # 将更新后的data写入total.json文件
29 | with open('src.json', 'w',encoding='utf-8') as f:
30 | json.dump(data, f)
31 |
32 | with open(new_file_name, 'r',encoding='utf-8') as f:
33 | data = json.load(f)
34 |
35 |
36 | content = f"{date}🕖 [今日单词]✅\n"
37 | for index,d in enumerate(data,1):
38 | content += f"{index}. 【{d['word']}】\n"
39 | content += f"mean:{d['mean']} {d['phonetic_symbol']}\n"
40 |
41 | content += "今天也是元气满满的一天!✨"
42 |
43 | print(content)
44 |
45 | if __name__ == '__main__':
46 | get_words()
--------------------------------------------------------------------------------
/PerpetualCalendar/test.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | import requests
3 | from pprint import pprint
4 | # https://api.aa1.cn/doc/perpetual-calendar.html
5 | """
6 | dataSource 是 string LOCAL_PERPETUAL_CALENDAR
7 | calendarType 是 string (默认)日历类型:值必须为gregorian(阳历)或lunar(阴历)
8 | data 是 string 日期格式:yyyy-MM-dd
9 | """
10 | url = "https://api.songzixian.com/api/perpetual-calendar"
11 | day = datetime.now().strftime("%Y-%m-%d")
12 | params = {
13 | "dataSource":"LOCAL_PERPETUAL_CALENDAR",
14 | "calendarType":"lunar",
15 | "data":day
16 | }
17 | print(day)
18 | response = requests.get(url=url,params=params)
19 | print(response.url)
20 | pprint(response.json())
21 | """
22 | {'code': 200,
23 | 'data': {'gregorianInfo': {'date': '2023-11-18', 'dayOfWeek': '星期六'},
24 | 'lunarInfo': {'chineseDate': '二〇二三年十月初六',
25 | 'chineseZodiac': '兔',
26 | 'day': 6,
27 | 'leapMonth': False,
28 | 'month': 10,
29 | 'year': 2023},
30 | 'traditionalChineseInfo': {'currentJieQi': '',
31 | 'dayStemBranch': '庚辰日',
32 | 'monthStemBranch': '癸亥月',
33 | 'nextJieQiName': '小雪',
34 | 'nextJieQiTime': '2023-11-22 22:02:29',
35 | 'yearStemBranch': '癸卯年'}},
36 | 'message': '正常响应',
37 | 'requestId': '1725722671976681472'}
38 | """
--------------------------------------------------------------------------------
/Almanac/Almanac.py:
--------------------------------------------------------------------------------
1 | import plugins # 导入自定义的插件模块
2 | from plugins import * # 导入其他自定义插件
3 | from config import conf # 导入配置文件
4 | from datetime import datetime
5 | from .get_data import get_almanac
6 | from bridge.context import ContextType
7 | from bridge.reply import Reply, ReplyType
8 | from common.log import logger
9 |
10 |
11 | @plugins.register(
12 | name="黄历", # 插件的名称
13 | desire_priority=1, # 插件的优先级
14 | hidden=False, # 插件是否隐藏
15 | desc="黄历", # 插件的描述
16 | version="1.0", # 插件的版本号
17 | author="XcNGG", # 插件的作者
18 | )
19 | class Almanac(Plugin):
20 | def __init__(self):
21 | super().__init__()
22 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
23 | logger.info("[Almanac-XcNGG] inited") # 初始化插件时打印一条消息
24 |
25 | def on_handle_context(self, e_context: EventContext):
26 | if e_context["context"].type != ContextType.TEXT:
27 | return
28 | content = e_context["context"].content.strip()
29 | if content == "黄历":
30 | almanac_key = conf().get("almanac_key")
31 | date = datetime.now().strftime("%Y-%m-%d")
32 | reply_content = get_almanac(key=almanac_key,date=date)
33 | reply = Reply()
34 | reply.type = ReplyType.TEXT
35 | reply.content = reply_content
36 | e_context["reply"] = reply
37 | e_context.action = EventAction.BREAK_PASS
38 |
39 |
40 | def get_help_text(self, **kwargs):
41 | help_text = "关键词【黄历】By XcNgg"
42 | return help_text
43 |
--------------------------------------------------------------------------------
/poetry/Poety.py:
--------------------------------------------------------------------------------
1 | import plugins
2 | from bridge.context import ContextType
3 | from bridge.reply import Reply, ReplyType
4 | from plugins import *
5 | from bridge import bridge
6 | from common.expired_dict import ExpiredDict
7 | from common import const
8 | import os
9 | from .test import get_data
10 |
11 | @plugins.register(
12 | name="诗词",
13 | # name="linkai",
14 | desc="随机诗词",
15 | version="0.1",
16 | author="XcNGG",
17 | desire_priority=0, # 权重值
18 | # hidden = False, # 插件是否隐藏
19 | )
20 | class LinkAI(Plugin):
21 | def __init__(self):
22 | super().__init__()
23 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
24 | logger.info(f"[诗词] inited ")
25 |
26 | def on_handle_context(self, e_context: EventContext):
27 | """
28 | 消息处理逻辑
29 | :param e_context: 消息上下文
30 | """
31 | if e_context["context"].type != ContextType.TEXT:
32 | return
33 |
34 | content = e_context["context"].content.strip()
35 |
36 | if content == "诗词":
37 | from_who, hitokoto, _from = get_data()
38 | response = f"{hitokoto} \n --{from_who} · 《{_from}》"
39 |
40 | reply = Reply()
41 | reply.type = ReplyType.TEXT
42 | reply.content = response
43 |
44 | e_context["reply"] = reply
45 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
46 |
47 | def get_help_text(self, verbose=False, **kwargs):
48 | help_text = "关键词【诗词】"
49 | return help_text
50 |
51 |
52 |
--------------------------------------------------------------------------------
/FishCalendar/FishCalendar.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 | import json
3 | import os
4 | import requests
5 | import plugins
6 | from bridge.context import ContextType
7 | from bridge.reply import Reply, ReplyType
8 | from common.log import logger
9 | from plugins import *
10 |
11 |
12 | @plugins.register(
13 | name="摸鱼日历",
14 | desire_priority=0,
15 | # namecn="摸鱼日历",
16 | desc="输入关键词'摸鱼日历'即可获取今日摸鱼日历哦-By XcNGG",
17 | version="1.0",
18 | author="XcNGG",
19 | )
20 | class FishCalendar(Plugin):
21 | def __init__(self):
22 | super().__init__()
23 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
24 | logger.info("[FishCalendar-XcNGG] inited.")
25 |
26 | def on_handle_context(self, e_context: EventContext):
27 |
28 | content = e_context["context"].content # 获取事件上下文中的消息内容
29 | if content == "摸鱼日历": # 如果消息内容为 "摸鱼日历"
30 | url = "https://api.vvhan.com/api/moyu?type=json"
31 | response = requests.get(url).json()
32 | status = response.get('success', False)
33 | if status:
34 | img_url = response.get('url', 'https://api.vvhan.com/api/moyu')
35 | logger.info(f"获取日历状态成功,今日日历:{img_url}")
36 | reply = Reply()
37 | reply.type = ReplyType.IMAGE_URL
38 | reply.content = img_url
39 | e_context["reply"] = reply
40 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
41 | else:
42 | logger.log("获取日历状态失败")
43 |
44 |
45 | def get_help_text(self, **kwargs):
46 | help_text = "关键词【摸鱼日历】By XcNGG"
47 | return help_text
--------------------------------------------------------------------------------
/已废弃/WorkCalendar/WorkCalendar.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 | import json
3 | import os
4 | import requests
5 | import plugins
6 | from bridge.context import ContextType
7 | from bridge.reply import Reply, ReplyType
8 | from common.log import logger
9 | from plugins import *
10 |
11 | @plugins.register(
12 | # name="WorkCalendar",
13 | desire_priority=0,
14 | name="工作日历",
15 | desc="输入关键词'工作日历'即可获取工作日历哦-By XcNGG",
16 | version="1.0",
17 | author="XcNGG",
18 | )
19 | class WorkCalendar(Plugin):
20 | def __init__(self):
21 | super().__init__()
22 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
23 | logger.info("[WorkCalendar-XcNGG] inited.")
24 |
25 | def on_handle_context(self, e_context: EventContext):
26 |
27 | content = e_context["context"].content # 获取事件上下文中的消息内容
28 | if content == "工作日历": # 如果消息内容为 "工作日历"
29 | url = "https://api.vvhan.com/api/zhichang?type=json"
30 | response = requests.get(url).json()
31 | status = response.get('success', False)
32 | if status:
33 | img_url = response.get('url', 'https://api.vvhan.com/api/moyu')
34 | logger.info(f"获取工作日历状态成功,今日日历:{img_url}")
35 | reply = Reply()
36 | reply.type = ReplyType.IMAGE_URL
37 | reply.content = img_url
38 | e_context["reply"] = reply
39 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
40 | else:
41 | logger.log("获取工作日历状态失败")
42 |
43 |
44 | def get_help_text(self, **kwargs):
45 | help_text = "关键词【工作日历】By XcNGG"
46 | return help_text
--------------------------------------------------------------------------------
/SearchIP/IPInfo.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from my_fake_useragent import UserAgent
3 | from common.log import logger
4 |
5 | def ip_info(ip):
6 | content = ""
7 | try:
8 | headers = {
9 | "authority": "api.uutool.cn",
10 | "accept": "application/json, text/javascript, */*; q=0.01",
11 | "accept-language": "zh-CN,zh;q=0.9",
12 | "cache-control": "no-cache",
13 | "origin": "https://uutool.cn",
14 | "pragma": "no-cache",
15 | "referer": "https://uutool.cn/",
16 | "sec-ch-ua": "^\\^Google",
17 | "sec-ch-ua-mobile": "?0",
18 | "sec-ch-ua-platform": "^\\^Windows^^",
19 | "sec-fetch-dest": "empty",
20 | "sec-fetch-mode": "cors",
21 | "sec-fetch-site": "same-site",
22 | "user-agent": UserAgent().random()
23 | }
24 | url = f"https://api.uutool.cn/ip/cz/{ip}"
25 | response = requests.get(url, headers=headers).json()
26 | status = response.get('status', 0)
27 | if status:
28 | content += f"【所属地区】{response.get('data', '未知地区').get('area', '未知地区')}\n"
29 | content += f"【更多信息】{response.get('data', '未知').get('extra', '未知')}\n"
30 | else:
31 | content += f"【请求状态】请求失败\n"
32 | content += f"【所属地区】未知地区\n"
33 | content += f"【更多信息】未知信息\n"
34 | logger.info(content)
35 | except Exception as e:
36 | content += f"【请求错误】发生错误{e}\n"
37 | logger.error(content)
38 | return content
39 |
40 |
41 |
42 | if __name__ == '__main__':
43 | ip = "123.23.2.3"
44 | content = f"【🔎 {ip}】\n"
45 | content += ip_info(ip)
46 | print(content)
--------------------------------------------------------------------------------
/CTFCalendar/CTFCalendar.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 | import json
3 | import os
4 | import requests
5 | import plugins
6 | from bridge.context import ContextType
7 | from bridge.reply import Reply, ReplyType
8 | from plugins import *
9 | from .GetCalendar import get_calendar
10 |
11 | @plugins.register(
12 | # name="CTFCalendar",
13 | name="CTF比赛日历",
14 | desire_priority=0,
15 | # namecn="CTF比赛日历",
16 | desc="CTF比赛日历",
17 | version="1.0.0",
18 | author="XcNGG",
19 | )
20 | class CTFCalendar(Plugin):
21 | def __init__(self):
22 | super().__init__()
23 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
24 | logger.info("[CTFCalendar-XcNGG] inited.")
25 |
26 | def on_handle_context(self, e_context: EventContext):
27 | if e_context["context"].type != ContextType.TEXT:
28 | return
29 | content = e_context["context"].content.stirp() # 获取事件上下文中的消息内容
30 | try:
31 | if content in ['CTF日历','ctf日历','ctf','CTF']:
32 | reply_content = get_calendar()
33 | reply = Reply()
34 | reply.type = ReplyType.TEXT
35 | reply.content = reply_content
36 | e_context["reply"] = reply
37 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
38 | except Exception as e:
39 | logger.error("出现错误,获取日历失败")
40 | reply = Reply()
41 | reply.type = ReplyType.ERROR
42 | reply.content = f'获取日历失败!\n{e}'
43 | e_context["reply"] = reply
44 | e_context.action = EventAction.BREAK_PASS
45 |
46 |
47 | def get_help_text(self, **kwargs):
48 | help_text = "关键词【CTF日历】(大小写均可) By XcNGG"
49 | return help_text
--------------------------------------------------------------------------------
/SearchDomain/CanRegister.py:
--------------------------------------------------------------------------------
1 | """
2 | 查看域名是否注册
3 | """
4 | from my_fake_useragent import UserAgent
5 | import requests
6 | from common.log import logger
7 |
8 |
9 | def can_register(domain):
10 | content = ""
11 | try:
12 | headers = {
13 | "authority": "api.vvhan.com",
14 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
15 | "accept-language": "zh-CN,zh;q=0.9",
16 | "cache-control": "no-cache",
17 | "pragma": "no-cache",
18 | "sec-ch-ua": "^\\^Google",
19 | "sec-ch-ua-mobile": "?0",
20 | "sec-ch-ua-platform": "^\\^Windows^^",
21 | "sec-fetch-dest": "document",
22 | "sec-fetch-mode": "navigate",
23 | "sec-fetch-site": "none",
24 | "sec-fetch-user": "?1",
25 | "upgrade-insecure-requests": "1",
26 | "user-agent": UserAgent().random()
27 | }
28 |
29 | url = "https://api.vvhan.com/api/dm"
30 | params = {
31 | "url": domain
32 | }
33 | response_data = requests.get(url=url, headers=headers,params=params).json()
34 | # print(response_data)
35 | if response_data.get('success',False):
36 | content += f"【注册信息】:{response_data['message']}\n"
37 | else:
38 | content +=f"【注册信息】:获取失败\n"
39 | logger.info(content)
40 | except Exception as e:
41 | content += f"【注册信息】:发生错误:{e}\n"
42 | logger.error(content)
43 |
44 | return content
45 |
46 | if __name__ == '__main__':
47 | content = ''
48 | domain = '8.8.8.8'
49 | "{'success': True, 'domain': 'google', 'message': '不可注册'}"
50 | content += can_register(domain=domain)
51 | print(content)
--------------------------------------------------------------------------------
/VulnerabilityIntelligence/VulnerabilityIntelligence.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 |
3 | import json
4 | import os
5 | import requests
6 | import plugins
7 | from bridge.context import ContextType
8 | from bridge.reply import Reply, ReplyType
9 | from common.log import logger
10 | from plugins import *
11 | from .SearchCNNVD import *
12 |
13 |
14 | @plugins.register(
15 | name="漏洞情报",
16 | desire_priority=0,
17 | hidden=True,
18 | desc="漏洞搜索,支持CNNVD",
19 | version="0.1",
20 | author="XcNGG",
21 | )
22 | class VulnerabilityIntelligence(Plugin):
23 | def __init__(self):
24 | super().__init__()
25 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
26 | logger.info("[VulnerabilityIntelligence] inited.")
27 |
28 | def on_handle_context(self, e_context: EventContext):
29 | if e_context["context"].type != ContextType.TEXT:
30 | return
31 | content = e_context["context"].content.strip()
32 | # 判断匹配CNNVD的类型
33 | if content.startswith("CNNVD-"):
34 | search_cnnvd(number=content,e_context=e_context)
35 |
36 | # 判断匹配CVE的类型
37 | if content.startswith("CVE-"):
38 | search_cnnvd(number=content,e_context=e_context)
39 |
40 |
41 | def get_help_text(self, **kwargs):
42 | help_text = "-------------------------\n"
43 | help_text += "支持CNNVD查询,CVE查询\n"
44 | help_text += "快速查询:关键词【漏洞编号】\n"
45 | help_text += "例如: CNNVD-202311-2(注意大写)\n"
46 | help_text += "-------------------------\n"
47 |
48 | return help_text
49 |
50 |
51 | def _send_info(e_context: EventContext, content: str):
52 | reply = Reply(ReplyType.TEXT, content)
53 | channel = e_context["channel"]
54 | channel.send(reply, e_context["context"])
55 |
--------------------------------------------------------------------------------
/SearchDomain/IsExtranet.py:
--------------------------------------------------------------------------------
1 | """
2 | 查看域名是否被墙
3 | """
4 | import requests
5 | from my_fake_useragent import UserAgent
6 | from common.log import logger
7 |
8 | def is_extranet(domain):
9 | content = ""
10 | try:
11 | headers = {
12 | "authority": "api.vvhan.com",
13 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
14 | "accept-language": "zh-CN,zh;q=0.9",
15 | "cache-control": "no-cache",
16 | "pragma": "no-cache",
17 | "sec-ch-ua": "^\\^Google",
18 | "sec-ch-ua-mobile": "?0",
19 | "sec-ch-ua-platform": "^\\^Windows^^",
20 | "sec-fetch-dest": "document",
21 | "sec-fetch-mode": "navigate",
22 | "sec-fetch-site": "none",
23 | "sec-fetch-user": "?1",
24 | "upgrade-insecure-requests": "1",
25 | "user-agent": UserAgent().random()
26 | }
27 |
28 | url = "https://api.vvhan.com/api/qiang"
29 | params = {
30 | "url": domain
31 | }
32 | response = requests.get(url, headers=headers, params=params)
33 | response_data = response.json()
34 | if response_data.get('success',False):
35 | content += f"【梯子状态】{response_data['msg']}\n"
36 | else:
37 | content += f"【梯子状态】获取失败\n"
38 | logger.info(content)
39 | except Exception as e:
40 | content += f"【梯子状态】发生错误-{e}\n"
41 | logger.error(content)
42 |
43 | return content
44 |
45 | if __name__ == '__main__':
46 | """
47 | {'success': True, 'domain': 'google.com', 'msg': '被墙了'}
48 | """
49 | domain = 'google.com'
50 | print(is_extranet(domain))
51 |
52 |
--------------------------------------------------------------------------------
/SearchDomain/SearchDomain.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 | import json
3 | import os
4 | import requests
5 | import plugins
6 | from bridge.context import ContextType
7 | from bridge.reply import Reply, ReplyType
8 | from common.log import logger
9 | from plugins import *
10 |
11 | from .DomainInfo import domain_info
12 | from .IsExtranet import is_extranet
13 | from .DomainDNS import domain_dns
14 | from .CanRegister import can_register
15 |
16 |
17 | @plugins.register(
18 | # name="SearchDomain",
19 | name="域名查询",
20 | desire_priority=0,
21 | # namecn="备案查询",
22 | desc="输入关键词(注意小写)'domain baidu.com'即可查询域名信息哦-By XcNGG",
23 | version="1.4",
24 | author="XcNGG",
25 | )
26 | class SearchDomain(Plugin):
27 | def __init__(self):
28 | super().__init__()
29 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
30 | logger.info("[SearchDomain-XcNGG] inited.")
31 |
32 | def on_handle_context(self, e_context: EventContext):
33 | content = e_context["context"].content
34 | reply = Reply()
35 | reply.type = ReplyType.TEXT
36 | # 获取事件上下文中的消息内容
37 | try:
38 | if content.startswith("domain "):
39 | domain = content.split(' ')[-1]
40 | reply.content = f"【🔎域名: {domain}】\n"
41 | reply.content += domain_info(domain)
42 | reply.content += can_register(domain)
43 | reply.content += is_extranet(domain)
44 | reply.content += domain_dns(domain)
45 |
46 | e_context["reply"] = reply
47 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
48 | except Exception as e:
49 | reply.content = f"【查询域名】:发送错误:{e}\n"
50 |
51 | def get_help_text(self, **kwargs):
52 | help_text = "关键词【domain baidu.com】(注意小写)By XcNGG"
53 | return help_text
--------------------------------------------------------------------------------
/WindowsHostInfo/WindowsHostInfo.py:
--------------------------------------------------------------------------------
1 | from .systemfuc import *
2 | import plugins # 导入自定义的插件模块
3 | from bridge.reply import Reply, ReplyType # 导入用于构建回复消息的类
4 | from plugins import * # 导入其他自定义插件
5 |
6 | @plugins.register(
7 | # name="WindowsHostInfo", # 插件的EN名称
8 | name="Windows主机巡检", # 插件的CN名称
9 | desire_priority=0, # 插件的优先级
10 | hidden=True, # 插件是否隐藏
11 | desc="Windows主机巡检插件", # 插件的描述
12 | version="1.0", # 插件的版本号
13 | author="XcNGG", # 插件的作者
14 | )
15 | class WindowsHostInfo(Plugin):
16 | def __init__(self):
17 | super().__init__()
18 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
19 | logger.info("[WindowsHostInfo-XcNGG] inited") # 初始化插件时打印一条消息
20 |
21 | def on_handle_context(self, e_context: EventContext):
22 | content = e_context["context"].content # 获取事件上下文中的消息内容
23 | if content == "主机巡检": # 如果消息内容为 "主机巡检"
24 | reply = Reply() # 创建回复消息对象
25 | reply.type = ReplyType.TEXT # 设置回复消息的类型为文本
26 | system_data = GetFullSystemData()
27 | result = f"""【主机时间】:{system_data['boot']['datetime']}
28 | 【主机系统】:{GetSystemVersion()}
29 | 【CPU信息】:{system_data['cpu']['cpu_name']}
30 | 【CPU占用】:{str(system_data['cpu']['used'] * 10) + '%'}
31 | 【内存占用】:{str(round(system_data['mem']['menUsedPercent'], 1)) + '%'}
32 | 【持续运行】:{round(system_data['boot']['runtime'] / 3600, 2)} 小时
33 | 【磁盘占用】:
34 | """
35 | disk_info = system_data['disk']
36 | for disk in disk_info:
37 | info = f" [{disk['path']}]占用:{str(round(disk['size']['percent'], 2))}%\n"
38 | result += info
39 | logger.info(result)
40 | reply.content = result # 设置回复消息的内容
41 |
42 | e_context["reply"] = reply
43 | e_context.action = EventAction.BREAK_PASS
44 |
45 |
46 | def get_help_text(self, **kwargs):
47 | help_text = "关键词【主机巡检】By XcNgg"
48 | return help_text
49 |
--------------------------------------------------------------------------------
/SearchIP/SearchIP.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 | import json
3 | import os
4 | import requests
5 | import plugins
6 | from bridge.context import ContextType
7 | from bridge.reply import Reply, ReplyType
8 | from common.log import logger
9 | from plugins import *
10 | from .IPInfo import ip_info
11 | from .IPHistory import ip_history
12 |
13 | @plugins.register(
14 | # name="SearchIP",
15 | name="IP查询",
16 | desire_priority=0,
17 | # namecn="IP归属",
18 | desc="输入关键词(注意小写)'ip xx.xx.xx.xx'即可查询IP归属地哦-By XcNGG",
19 | version="1.2.1",
20 | author="XcNGG",
21 | )
22 | class SearchIp(Plugin):
23 | def __init__(self):
24 | super().__init__()
25 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
26 | logger.info("[SearchIP-XcNGG] inited.")
27 |
28 | def on_handle_context(self, e_context: EventContext):
29 | content = e_context["context"].content # 获取事件上下文中的消息内容
30 | try:
31 | if content.startswith("ip "):
32 | ip = content.split(' ')[-1]
33 | reply = Reply()
34 | reply.type = ReplyType.TEXT
35 | reply.content = f"【🔎 {ip}】\n"
36 | # IP基本信息
37 | reply.content += ip_info(ip)
38 | # 历史IP DNS 解析记录
39 | max_data = 15 # 最大展示条数
40 | reply.content += ip_history(ip,max_data=max_data)
41 | e_context["reply"] = reply
42 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
43 |
44 | except Exception as e:
45 | logger.error("出现错误,查询IP失败!")
46 | reply = Reply()
47 | reply.type = ReplyType.TEXT
48 | reply.content = f'[ERROR]\nIP查询失败!\n{e}'
49 | e_context["reply"] = reply
50 | e_context.action = EventAction.BREAK_PASS
51 |
52 |
53 | def get_help_text(self, **kwargs):
54 | help_text = "关键词【ip 8.8.8.8】(注意小写)By XcNGG"
55 | return help_text
--------------------------------------------------------------------------------
/Almanac/get_data.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | import requests
3 |
4 | def get_almanac(key,date):
5 | url = f"http://v.juhe.cn/laohuangli/d?date={date}&key={key}"
6 | response = requests.get(url=url,timeout=3)
7 | if response.status_code == 200:
8 | response_data =response.json()
9 | result = response_data.get('result')
10 | yangli = result.get('yangli')
11 | yinli = result.get('yinli')
12 | wuxing = result.get('wuxing')
13 | chongsha = result.get('chongsha')
14 | baiji = result.get('baiji')
15 | jishen = result.get('jishen')
16 | yi = result.get('yi')
17 | xiongshen = result.get('xiongshen')
18 | ji = result.get('ji')
19 |
20 | content = f"📅老黄历 [{yangli}]\n"
21 | content += f"【阴历】\t{yinli}\n"
22 | content += f"【五行】\t{wuxing}\n"
23 | content += f"【冲煞】\t{chongsha}\n"
24 | content += f"【百忌】\t{baiji}\n"
25 | content += f"【吉神】\t{jishen}\n"
26 | content += f"【凶神】\t{xiongshen}\n"
27 | content += f"【宜】\t{yi}\n"
28 | content += f"【忌】\t{ji}\n"
29 | return content
30 | else:
31 | return f"老黄历获取失败!{response.status_code}"
32 |
33 |
34 | # {
35 | # "reason": "successed",
36 | # "result": {
37 | # "id": "4915",
38 | # "yangli": "2023-11-27",
39 | # "yinli": "癸卯(兔)年十月十五",
40 | # "wuxing": "霹雳火 满执位",
41 | # "chongsha": "冲羊(癸未)煞东",
42 | # "baiji": "己不破券二比并亡 丑不冠带主不还乡",
43 | # "jishen": "月德合 守日 天巫 福德 玉宇 玉堂",
44 | # "yi": "开光 裁衣 安门 会亲友 安床 结网 理发",
45 | # "xiongshen": "月厌 地火 九空 大煞 归忌",
46 | # "ji": "嫁娶 冠笄 出行 祈福 安葬 伐木 入宅 移徙 出火 栽种 动土 上梁"
47 | # },
48 | # "error_code": 0
49 | # }
50 |
51 |
52 |
53 | if __name__ == '__main__':
54 | key = "5caa483c89be598ddfa80ac738ce4b82"
55 | date = datetime.now().strftime("%Y-%m-%d")
56 | response = get_almanac(key,date)
57 |
58 |
--------------------------------------------------------------------------------
/SearchDomain/DomainInfo.py:
--------------------------------------------------------------------------------
1 | """
2 | 基本功能 查看域名信息
3 | """
4 | import requests
5 | from my_fake_useragent import UserAgent
6 | from common.log import logger
7 |
8 | def domain_info(domain):
9 | content = ""
10 | try:
11 | headers = {
12 | "authority": "api.uutool.cn",
13 | "accept": "application/json, text/javascript, */*; q=0.01",
14 | "accept-language": "zh-CN,zh;q=0.9",
15 | "cache-control": "no-cache",
16 | "origin": "https://uutool.cn",
17 | "pragma": "no-cache",
18 | "referer": "https://uutool.cn/",
19 | "sec-ch-ua": "^\\^Google",
20 | "sec-ch-ua-mobile": "?0",
21 | "sec-ch-ua-platform": "^\\^Windows^^",
22 | "sec-fetch-dest": "empty",
23 | "sec-fetch-mode": "cors",
24 | "sec-fetch-site": "same-site",
25 | "user-agent": UserAgent().random()
26 | }
27 | url = "https://api.uutool.cn/beian/icp/"
28 | data = {
29 | "domain": domain
30 | }
31 | response_data = requests.post(url, headers=headers, data=data).json()
32 | status = response_data.get('status',0)
33 | if status:
34 | # {'status': 1,
35 | # 'data':
36 | # {'domain': 'baidu.com',
37 | # 'is_icp': 1,
38 | # 'icp_org': '北京百度网讯科技有限公司',
39 | # 'icp_no': '京ICP证030173号-1'
40 | # },
41 | # 'req_id': 'e29115d357a76b547871'}
42 | content += f"【是否备案】{response_data.get('data', '未知').get('is_icp', '未知')}\n"
43 | content += f"【所属机构/个人】{response_data.get('data', '未知').get('icp_org', '未知')}\n"
44 | content += f"【备案号】{response_data.get('data', '未知').get('icp_no', '未知')}\n"
45 | else:
46 | content += f"【备案信息】获取失败\n"
47 | logger.info(content)
48 | except Exception as e:
49 | content += f"【备案信息】发送错误:{e}\n"
50 | logger.error(content)
51 |
52 | return content
53 |
54 |
55 |
56 | if __name__ == '__main__':
57 | domain = 'baidu.com'
58 | print(domain_info(domain))
59 |
--------------------------------------------------------------------------------
/CTFCalendar/GetCalendar.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import icalendar
3 | from datetime import datetime, timedelta
4 | from my_fake_useragent import UserAgent
5 |
6 | def get_calendar():
7 | url = "https://api.ctfhub.com/User_API/Event/getAllICS"
8 | # 获取今天和最近7天的日期范围
9 | today = datetime.now().date()
10 | set_start_date = today - timedelta(days=3)
11 | set_end_date = today + timedelta(days=4)
12 | # 计数
13 | count = 0
14 | # 标题
15 | content = f"【CTF比赛日历】(仅近7日未结束或未开始的线上竞赛)\n"
16 | content += "-------------\n"
17 | response = requests.get(url=url,headers={'user-agent':UserAgent().random()})
18 | # 解析日历
19 | calendar = icalendar.Calendar.from_ical(response.text)
20 | # 遍历日历事件
21 | for event in calendar.walk('VEVENT'):
22 | start_date = event.get('dtstart').dt.date()
23 | end_date = event.get('DTEND').dt.date()
24 | summary = event.get('summary')
25 | # print(summary)
26 | # 检查事件是否在日期范围内
27 | if (start_date >= set_start_date and end_date <= set_end_date) and (end_date >= today):
28 | description = event.get('description')
29 | # 筛选线上的比赛
30 | if description.startswith('线上 '):
31 | url = event.get('url')
32 | # 在这里可以根据需要处理符合条件的日历事件
33 | # print('Summary:', summary)
34 | content += f"竞赛名称:《{summary}》\n"
35 | content += f"比赛描述: {description}\n"
36 | content += f"开始时间: {start_date}\n"
37 | content += f"结束时间: {end_date}\n"
38 | content += f"比赛链接: {url}\n"
39 | content += "-------------\n"
40 | count += 1
41 | # print(count)
42 |
43 | if count >0:
44 | content += f"近期共【{count}】场比赛,请及时关注!\n"
45 | content += "👍👍🏻👍🏼全部写出来奖励你大拇哥👍🏽👍🏾👍🏿"
46 | else:
47 | content += "当前数据源显示近期无比赛"
48 |
49 | print(content)
50 | return content
51 |
52 |
53 | # 解析iCalendar文件
54 | # calendar = icalendar.Calendar.from_ical(data)
55 | #
56 | # 遍历日历事件
57 | # for event in calendar.walk('VEVENT'):
58 | # summary = event.get('summary')
59 | # start = event.get('dtstart').dt
60 | # end = event.get('dtend').dt
61 | # description = event.get('description')
62 | # url = event.get('url')
63 | #
64 | # # 在这里可以根据需要处理日历事件的各个属性
65 | #
66 | # print('Summary:', summary)
67 | # print('Start:', start)
68 | # print('End:', end)
69 | # print('Description:', description)
70 | # print('URL:', url)
71 | # print()
72 |
73 | if __name__ == '__main__':
74 | get_calendar()
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98 | __pypackages__/
99 |
100 | # Celery stuff
101 | celerybeat-schedule
102 | celerybeat.pid
103 |
104 | # SageMath parsed files
105 | *.sage.py
106 |
107 | # Environments
108 | .env
109 | .venv
110 | env/
111 | venv/
112 | ENV/
113 | env.bak/
114 | venv.bak/
115 |
116 | # Spyder project settings
117 | .spyderproject
118 | .spyproject
119 |
120 | # Rope project settings
121 | .ropeproject
122 |
123 | # mkdocs documentation
124 | /site
125 |
126 | # mypy
127 | .mypy_cache/
128 | .dmypy.json
129 | dmypy.json
130 |
131 | # Pyre type checker
132 | .pyre/
133 |
134 | # pytype static type analyzer
135 | .pytype/
136 |
137 | # Cython debug symbols
138 | cython_debug/
139 |
--------------------------------------------------------------------------------
/TopHub163/Tophub163.py:
--------------------------------------------------------------------------------
1 | import requests # 导入用于发送 HTTP 请求的库
2 | import json # 导入用于处理 JSON 数据的库
3 | import re # 导入用于正则表达式匹配的库
4 | import plugins # 导入自定义的插件模块
5 | from bridge.reply import Reply, ReplyType # 导入用于构建回复消息的类
6 | from plugins import * # 导入其他自定义插件
7 | from config import conf # 导入配置文件
8 |
9 | @plugins.register(
10 | # name="Tophub163", # 插件的名称
11 | name="网易新闻热榜", # 插件的名称
12 | desire_priority=1, # 插件的优先级
13 | hidden=False, # 插件是否隐藏
14 | desc="网易新闻热榜", # 插件的描述
15 | version="1.1", # 插件的版本号
16 | author="XcNGG", # 插件的作者
17 | )
18 | class Tophub163(Plugin):
19 | def __init__(self):
20 | super().__init__()
21 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
22 | logger.info("[Tophub163-XcNGG] inited") # 初始化插件时打印一条消息
23 |
24 | def on_handle_context(self, e_context: EventContext):
25 | content = e_context["context"].content # 获取事件上下文中的消息内容
26 | if content == "网易热榜": # 如果消息内容为 "网易热榜"
27 | token = conf().get("tophub_token") # 从配置文件中获取 tophub_token
28 | news_type = conf().get("tophub_type") # 从配置文件中获取 tophub_type
29 | url = "https://v2.alapi.cn/api/new/toutiao" # API 的 URL
30 | payload = f"token={token}&type={news_type}&page=1"
31 | headers ={"Content-Type": "application/x-www-form-urlencoded"}# 请求头
32 |
33 | try:
34 | response = requests.request("POST", url, data=payload, headers=headers)# 发送 get 请求
35 | response.raise_for_status() # 抛出异常
36 | except requests.exceptions.RequestException as e:
37 | print(f"An error occurred when making the request: {e}") # 请求出错时打印错误消息
38 | return
39 | data = json.loads(response.text) # 解析返回的 JSON 数据
40 | news_data = data.get('data') # 获取新闻数据
41 |
42 | if news_data:
43 | reply = Reply() # 创建回复消息对象
44 | reply.type = ReplyType.TEXT # 设置回复消息的类型为文本
45 | reply.content = f"🔥今日新闻热榜【网易】🔎\n【关键词为'网易热榜'时,我会为你抓取今日新闻】\n" # 设置回复消息的内容
46 |
47 | for i, news_item in enumerate(news_data, 1):
48 | title = news_item.get('title', '未知标题').replace('\n','') # 获取新闻标题
49 | link = news_item.get('m_url', '未知链接').replace('\n','') # 获取新闻链接
50 | digest = news_item.get('digest', '未知摘要').replace('\n','') # 获取新闻摘要
51 | # 添加到回复内容中
52 | reply.content += f"No.{i}《{title}》\n【摘要:{digest}】\n🔗{link}\n"
53 |
54 | e_context["reply"] = reply
55 | e_context.action = EventAction.BREAK_PASS
56 | else:
57 | print("ERROR: Data not found in response")
58 |
59 | def get_help_text(self, **kwargs):
60 | help_text = "关键词【网易热榜】By XcNgg"
61 | return help_text
62 |
--------------------------------------------------------------------------------
/SearchIP/IPHistory.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import pprint
3 | from my_fake_useragent import UserAgent
4 | from common.log import logger
5 | def ip_history(ip,max_data = 10):
6 | set_time = 4 # 超时时间
7 | content = ""
8 | try:
9 | headers = {
10 | "authority": "api.pearktrue.cn",
11 | "accept": "application/json, text/javascript, */*; q=0.01",
12 | "accept-language": "zh-CN,zh;q=0.9",
13 | "cache-control": "no-cache",
14 | "origin": "https://api.aa1.cn",
15 | "pragma": "no-cache",
16 | "referer": "https://api.aa1.cn/",
17 | "sec-ch-ua": "^\\^Google",
18 | "sec-ch-ua-mobile": "?0",
19 | "sec-ch-ua-platform": "^\\^Windows^^",
20 | "sec-fetch-dest": "empty",
21 | "sec-fetch-mode": "cors",
22 | "sec-fetch-site": "cross-site",
23 | "user-agent": UserAgent().random()
24 | }
25 | url = "https://api.pearktrue.cn/api/website/sameip/"
26 | params = {
27 | "ip": ip
28 | }
29 |
30 | response_data = requests.get(url, headers=headers, params=params,timeout=set_time).json()
31 | if response_data['code'] == 200:
32 | content += f"【历史解析】共{response_data['count']}条"
33 | if len(response_data['data']) > max_data:
34 | content += f"(以下仅展示{max_data}条)\n"
35 | for history in response_data['data'][:max_data]:
36 | content += f"{history['domain']} | {history['time'].replace('----', '->')}\n"
37 | else:
38 | content += f"【历史解析】{response_data['msg']} | Http状态:{response_data['code']}\n"
39 | logger.info(content)
40 |
41 | except requests.exceptions.ReadTimeout:
42 | # requests.exceptions.ReadTimeout:HTTPSConnectionPool(host='api.pearktrue.cn', port=443): Read timed out.
43 | content += f"【历史解析】请求超过({set_time}秒),建议稍后再试\n"
44 | logger.error(content)
45 |
46 | except Exception as e:
47 | content += f"【历史解析】发生错误:{e}\n"
48 | logger.error(content)
49 |
50 | return content
51 | # pprint.pprint(response.json())
52 | # return response.json()
53 |
54 |
55 | if __name__ == '__main__':
56 | content = ""
57 | ip = "123.11.15.14"
58 | content += ip_history(ip,max_data=15)
59 | print(content)
60 |
61 |
62 | """
63 | {'api_source': '官方API网:https://api.pearktrue.cn/',
64 | 'code': 200,
65 | 'count': 100,
66 | 'data': [{'domain': 'baidu.cn', 'time': '20190604----20231119'},
67 | {'domain': 'www.zz666.com', 'time': '20220722----20231119'},
68 | {'domain': 'zz666.com', 'time': '20220724----20231119'},
69 | {'domain': '3365.com', 'time': '20220804----20231119'},
70 | {'domain': '4233.com', 'time': '20220823----20231119'},
71 | .....
72 | 'ip': '39.156.66.10',
73 | 'msg': '查询成功'}
74 | """
75 |
76 |
--------------------------------------------------------------------------------
/SearchDomain/DomainDNS.py:
--------------------------------------------------------------------------------
1 | """
2 | 查看域名DNS记录
3 | """
4 | import requests
5 | from my_fake_useragent import UserAgent
6 | from common.log import logger
7 |
8 |
9 | # 公用免费DNS
10 | public_dns_server ={
11 | "114.114.114.114": "电信联通移动全国通用DNS",
12 | "114.114.115.115": "电信联通移动全国通用DNS",
13 | "114.114.114.119": "电信联通移动全国通用DNS",
14 | "114.114.115.119": "电信联通移动全国通用DNS",
15 | "114.114.114.110": "电信联通移动全国通用DNS",
16 | "114.114.115.110": "电信联通移动全国通用DNS",
17 | "223.5.5.5": "阿里DNS",
18 | "223.6.6.6": "阿里DNS",
19 | "180.76.76.76": "百度DNS",
20 | "8.8.8.8": "谷歌DNS",
21 | "8.8.4.4": "谷歌DNS",
22 | "119.29.29.29":"腾讯DNS",
23 | "182.254.116.116": "腾讯备用DNS",
24 | "180.184.1.1": "字节跳动DNS",
25 | "180.184.2.2": "字节跳动DNS",
26 | "101.226.4.6": "360安全DNS(电信/铁通/移动)",
27 | "218.30.118.6": "360安全DNS(联通)",
28 | "1.2.4.8":"CNNIC中国互联网信息中心DNS"
29 | }
30 |
31 |
32 | def domain_dns(domain,dns_server="1.2.4.8"):
33 | """
34 | 查看域名DNS记录
35 | {
36 | "dns": "114.114.114.114",
37 | "type": "A",
38 | "domain": "www.baidu.com",
39 | "state": true,
40 | "record": [
41 | {
42 | "ip": "180.101.50.188",
43 | "ttl": 125
44 | },
45 | {
46 | "ip": "180.101.50.242",
47 | "ttl": 125
48 | }
49 | ]
50 | }
51 | """
52 | content = ""
53 | headers = {
54 | "Accept": "application/json, text/javascript, */*; q=0.01",
55 | "Accept-Language": "zh-CN,zh;q=0.9",
56 | "Cache-Control": "no-cache",
57 | "Connection": "keep-alive",
58 | "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
59 | "Origin": "http://www.ip33.com",
60 | "Pragma": "no-cache",
61 | "Referer": "http://www.ip33.com/",
62 | "User-Agent": UserAgent().random()
63 | }
64 | url = "http://api.ip33.com/dns/resolver"
65 | data = {
66 | "domain": domain,
67 | "dns": dns_server,
68 | "type": "A",
69 | }
70 | try:
71 | response_data = requests.post(url=url, headers=headers, data=data, verify=False).json()
72 | if isinstance(response_data, str):
73 | content += f"【DNS信息】:获取错误:{response_data}\n"
74 | logger.info(content)
75 | else:
76 | content += f"【DNS信息】:\n"
77 | content += f" -DNS服务器:{public_dns_server.get(response_data.get('dns',dns_server))}:{response_data.get('dns',dns_server)}\n"
78 | records = response_data.get('record')
79 | if len(records) > 0:
80 | for record in records:
81 | content += f" -A记录:[ip:{record.get('ip')} | ttl:{record.get('ttl')}]\n"
82 | except Exception as e:
83 | content += f'【DNS信息】:发生错误:{e}\n'
84 | logger.error(content)
85 |
86 | return content
87 |
88 |
89 | if __name__ == '__main__':
90 | domain = 'baidu.com'
91 | content = ''
92 | dns_info = domain_dns(domain)
93 | content += dns_info
94 | print(content)
95 |
96 |
97 |
--------------------------------------------------------------------------------
/CetsHelper/CetsHelper.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 | import json
3 | import os
4 | import requests
5 | import plugins
6 | from bridge.context import ContextType
7 | from bridge.reply import Reply, ReplyType
8 | from common.log import logger
9 | from plugins import *
10 | from datetime import datetime
11 | import random
12 |
13 | @plugins.register(
14 | name="CETs助手",
15 | desire_priority=900,
16 | hidden=True,
17 | desc="CETs助手",
18 | version="0.1",
19 | author="XcNGG",
20 | )
21 | class CetsHelper(Plugin):
22 | def __init__(self):
23 | super().__init__()
24 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
25 | logger.info("[CETs助手] inited.")
26 |
27 |
28 | def on_handle_context(self, e_context: EventContext):
29 | if e_context["context"].type != ContextType.TEXT:
30 | return
31 | content = e_context["context"].content.strip()
32 |
33 | if content == "今日单词":
34 | reply = Reply()
35 | reply.type = ReplyType.TEXT
36 | reply.content = self.get_words()
37 | e_context["reply"] = reply
38 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过
39 | elif content.startswith("发音 "):
40 | words = content.split('发音 ')[-1]
41 | reply = Reply()
42 | reply.type = ReplyType.FILE
43 | reply.content = self.get_voice(words=words)
44 |
45 | e_context["reply"] = reply
46 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
47 |
48 | def get_words(self):
49 | now_path = os.getcwd().replace("\\", "/") + "/"
50 | print(f"当前路径:{now_path}")
51 | # "E:\CodeProject\PythonProject\chatgpt-on-wechat\cet-4\"
52 | # 生成新的json文件名
53 | date = datetime.now().strftime('%Y-%m-%d')
54 | new_file_name = now_path + f"plugins/CetsHelper/data/{date}.json"
55 | print(f"new_file_name:{new_file_name}")
56 |
57 | src_path = now_path + "plugins/CetsHelper/data/total.json"
58 | print(f"src_path:{src_path}")
59 |
60 |
61 | if not os.path.exists(new_file_name):
62 | # 读取total.json文件
63 | with open(src_path, 'r', encoding='utf-8') as f:
64 | data = json.load(f)
65 |
66 | if len(data) >= 20:
67 | random_words = random.sample(data, 20)
68 | else:
69 | random_words = random.sample(data, len(data))
70 |
71 | with open(new_file_name, 'w', encoding='utf-8') as f:
72 | json.dump(random_words, f,indent=4)
73 |
74 |
75 | data = [word for word in data if word not in random_words]
76 |
77 | with open(src_path, 'w', encoding='utf-8') as f:
78 | json.dump(data, f,indent=4)
79 |
80 |
81 | with open(new_file_name, 'r', encoding='utf-8') as f:
82 | data = json.load(f)
83 |
84 | content = f"{date}🕖【今日单词】🔠\n"
85 | for index, d in enumerate(data, 1):
86 | content += f"{index}. {d['word']}\n"
87 | content += f"解释:{d['mean']}|音标:{d['phonetic_symbol']}\n"
88 | content += "✅今天也是元气满满的一天!✨"
89 | return content
90 |
91 | def get_voice(self,words):
92 | url = "http://dict.youdao.com/dictvoice?type=1&audio=" + words
93 | response = requests.get(url)
94 | now_path = os.getcwd().replace("\\", "/") + "/"
95 | path = r"plugins/CetsHelper/voice/"
96 | mp3_path = now_path+path+words+".mp3"
97 | with open(mp3_path, 'wb') as mp3:
98 | mp3.write(response.content)
99 | return mp3_path
100 |
101 |
102 |
103 | def get_help_text(self, **kwargs):
104 | help_text = "关键词【今日单词】获取今日单词清单\n关键词【发音 单词】获取单词发音\nBy XcNGG"
105 | return help_text
106 |
--------------------------------------------------------------------------------
/RandomWord/RandomWord.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 | import json
3 | import os
4 | import requests
5 | import plugins
6 | from bridge.context import ContextType
7 | from bridge.reply import Reply, ReplyType
8 | from common.log import logger
9 | from plugins import *
10 |
11 |
12 | @plugins.register(
13 | # name="RandomWord",
14 | name="随机语录",
15 | desire_priority=0,
16 | # namecn="随机语录",
17 | desc="关键词'随机语录'-By XcNGG",
18 | version="1.0",
19 | author="XcNGG",
20 | )
21 | class RandomWord(Plugin):
22 | def __init__(self):
23 | super().__init__()
24 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
25 | logger.info("[RandomWord-XcNGG] inited.")
26 |
27 | def on_handle_context(self, e_context: EventContext):
28 | content = e_context["context"].content # 获取事件上下文中的消息内容
29 | try:
30 | if content == "随机语录":
31 | headers = {
32 | "authority": "api.vvhan.com",
33 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
34 | "accept-language": "zh-CN,zh;q=0.9",
35 | "cache-control": "no-cache",
36 | "pragma": "no-cache",
37 | "sec-ch-ua": "^\\^Google",
38 | "sec-ch-ua-mobile": "?0",
39 | "sec-ch-ua-platform": "^\\^Windows^^",
40 | "sec-fetch-dest": "document",
41 | "sec-fetch-mode": "navigate",
42 | "sec-fetch-site": "none",
43 | "sec-fetch-user": "?1",
44 | "upgrade-insecure-requests": "1",
45 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
46 | }
47 |
48 | url = f"https://api.vvhan.com/api/ian?type=json"
49 | response = requests.get(url, headers=headers).json()
50 | status = response.get('success',False)
51 | if status:
52 | logger.info(f"查询[随机语录]成功")
53 | reply = Reply()
54 | reply.type = ReplyType.TEXT
55 | vhan = response.get("data").get("vhan")
56 | source = response.get("data").get("source")
57 | reply.content = f"{vhan} \n -----《{source}》"
58 | """
59 | { "success":true,
60 | "type":"Random",
61 | "data":
62 | {"id":4678,
63 | "vhan":"于千万人之中,遇见你所遇见的人;于千万年之中,时间的无涯荒野里,没有早一步,也没有晚一步,刚巧赶上了。 ",
64 | "source":"爱",
65 | "creator":"柔刃"
66 | }
67 | }
68 | """
69 | e_context["reply"] = reply
70 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
71 | else:
72 | logger.info(f"获取[随机语录]成功")
73 | reply = Reply()
74 | reply.type = ReplyType.TEXT
75 | reply.content = f"获取[随机语录]失败"
76 |
77 | e_context["reply"] = reply
78 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
79 |
80 | except Exception as e:
81 | logger.error("出现错误,获取[随机语录]失败")
82 | reply = Reply()
83 | reply.type = ReplyType.TEXT
84 | reply.content = f'[ERROR]\n获取[随机语录]失败!\n{e}'
85 | e_context["reply"] = reply
86 | e_context.action = EventAction.BREAK_PASS
87 |
88 | def get_help_text(self, **kwargs):
89 | help_text = "关键词【随机语录】By XcNGG"
90 | return help_text
--------------------------------------------------------------------------------
/CetsHelper/data/2023-11-26.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "initial": "K",
4 | "mean": "vt.\u543bvi.\u63a5\u543bn.\u543b",
5 | "phonetic_symbol": "/kis/",
6 | "word": "kiss"
7 | },
8 | {
9 | "initial": "D",
10 | "mean": "n.\u5bbf\u820d",
11 | "phonetic_symbol": "[d\u0254:m]",
12 | "word": "dorm"
13 | },
14 | {
15 | "initial": "H",
16 | "mean": "a.\u9965\u997f\u7684;\u6e34\u671b\u7684",
17 | "phonetic_symbol": "/\u2018h\u039b\u014bgri/",
18 | "word": "hungry"
19 | },
20 | {
21 | "initial": "R",
22 | "mean": "vt.\u5c55\u73b0;\u63ed\u793a\uff0c\u63ed\u9732",
23 | "phonetic_symbol": "/ri\u2019vi:l/",
24 | "word": "reveal"
25 | },
26 | {
27 | "initial": "O",
28 | "mean": "ad.\u53e6\u5916;\u8981\u4e0d\u7136",
29 | "phonetic_symbol": "/\u2018\u039b\u00f0\u0259waiz/",
30 | "word": "otherwise"
31 | },
32 | {
33 | "initial": "G",
34 | "mean": "n.\u4f53\u80b2\u9986\uff0c\u5065\u8eab\u623f",
35 | "phonetic_symbol": "/d\u0292im\u2019neizj\u0259m/",
36 | "word": "gymnasium"
37 | },
38 | {
39 | "initial": "F",
40 | "mean": "vt.\u9002\u5408;\u5b89\u88c5vi.\u9002\u5408",
41 | "phonetic_symbol": "/fit/",
42 | "word": "fit"
43 | },
44 | {
45 | "initial": "O",
46 | "mean": "n.\u7269\uff0c\u7269\u4f53;\u76ee\u7684",
47 | "phonetic_symbol": "/\u2018obd\u0292ikt\u0259b\u2019d\u0292ekt/",
48 | "word": "object"
49 | },
50 | {
51 | "initial": "C",
52 | "mean": "vt.\u521b\u9020;\u5f15\u8d77\uff0c\u4ea7\u751f",
53 | "phonetic_symbol": "/kri(:)\u2019eit/",
54 | "word": "create"
55 | },
56 | {
57 | "initial": "B",
58 | "mean": "vt.\u4f7f\u5e73\u8861;\u79f0n.\u5929\u5e73",
59 | "phonetic_symbol": "/\u2018b\u00e6l\u0259ns/",
60 | "word": "balance"
61 | },
62 | {
63 | "initial": "V",
64 | "mean": "a.\u5782\u76f4\u7684\uff0c\u7ad6\u5f0f\u7684",
65 | "phonetic_symbol": "/\u2018v\u0259:tik\u0259l/",
66 | "word": "vertical"
67 | },
68 | {
69 | "initial": "B",
70 | "mean": "n.\u6218\u5f79;\u6597\u4e89vi.\u4f5c\u6218",
71 | "phonetic_symbol": "/\u2018b\u00e6tl/",
72 | "word": "battle"
73 | },
74 | {
75 | "initial": "D",
76 | "mean": "a.\u5927\u80c6\u7684,\u52c7\u6562\u7684",
77 | "phonetic_symbol": "[\u2018de\u0259r\u026a\u014b]",
78 | "word": "daring"
79 | },
80 | {
81 | "initial": "N",
82 | "mean": "num.\u7b2c\u4e5d;\u4e5d\u5206\u4e4b\u4e00",
83 | "phonetic_symbol": "/nain\u03b8/",
84 | "word": "ninth"
85 | },
86 | {
87 | "initial": "A",
88 | "mean": "a.\u5b66\u9662\u7684;\u5b66\u672f\u7684",
89 | "phonetic_symbol": "/\u00e6k\u0259\u2019demik/",
90 | "word": "academic"
91 | },
92 | {
93 | "initial": "E",
94 | "mean": "vt.\u9009\u4e3e\uff0c\u63a8\u9009;\u9009\u62e9",
95 | "phonetic_symbol": "/i\u2019lekt/",
96 | "word": "elect"
97 | },
98 | {
99 | "initial": "M",
100 | "mean": "n.\u673a\u5668,\u673a\u5173,\u7ed3\u6784",
101 | "phonetic_symbol": "/m\u0259\u2019\u0283i:n\u0259ri/",
102 | "word": "machinery"
103 | },
104 | {
105 | "initial": "D",
106 | "mean": "n.\u91d1\u94a2\u77f3,\u94bb\u77f3;\u83f1\u5f62",
107 | "phonetic_symbol": "[\u2018dai\u0259m\u0259nd]",
108 | "word": "diamond"
109 | },
110 | {
111 | "initial": "T",
112 | "mean": "n.\u771f\u7406;\u771f\u5b9e;\u771f\u5b9e\u6027",
113 | "phonetic_symbol": "/tru:\u03b8/",
114 | "word": "truth"
115 | },
116 | {
117 | "initial": "R",
118 | "mean": "a.\u521a\u786c\u7684;\u50f5\u786c\u7684",
119 | "phonetic_symbol": "/\u2018rid\u0292id/",
120 | "word": "rigid"
121 | }
122 | ]
--------------------------------------------------------------------------------
/TodaysQuotationste/TodaysQuotationste.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 | import json
3 | import os
4 | import requests
5 | import plugins
6 | from bridge.context import ContextType
7 | from bridge.reply import Reply, ReplyType
8 | from common.log import logger
9 | from plugins import *
10 |
11 |
12 | @plugins.register(
13 | # name="TodaysQuotationste",
14 | desire_priority=0,
15 | name="每日语录",
16 | desc="关键词'每日语录'-By XcNGG",
17 | version="1.1",
18 | author="XcNGG",
19 | )
20 | class TodaysQuotationste(Plugin):
21 | def __init__(self):
22 | super().__init__()
23 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
24 | logger.info("[TodaysQuotationste-XcNGG] inited.")
25 |
26 | def on_handle_context(self, e_context: EventContext):
27 | content = e_context["context"].content # 获取事件上下文中的消息内容
28 | try:
29 | if content == "每日语录":
30 | headers = {
31 | "authority": "api.vvhan.com",
32 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
33 | "accept-language": "zh-CN,zh;q=0.9",
34 | "cache-control": "no-cache",
35 | "pragma": "no-cache",
36 | "sec-ch-ua": "^\\^Google",
37 | "sec-ch-ua-mobile": "?0",
38 | "sec-ch-ua-platform": "^\\^Windows^^",
39 | "sec-fetch-dest": "document",
40 | "sec-fetch-mode": "navigate",
41 | "sec-fetch-site": "none",
42 | "sec-fetch-user": "?1",
43 | "upgrade-insecure-requests": "1",
44 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
45 | }
46 |
47 | url = f"https://api.vvhan.com/api/en"
48 | response = requests.get(url, headers=headers).json()
49 | status = response.get('success',False)
50 | if status:
51 | logger.info(f"查询[每日语录]成功")
52 | reply = Reply()
53 | reply.type = ReplyType.TEXT
54 | month = response.get("data").get("month")
55 | day = response.get("data").get("day")
56 | zh = response.get("data").get("zh")
57 | en = response.get("data").get("en")
58 | reply.content = f"💬【{month}-{day}】\n【CN】{zh} \n【En】{en}"
59 | """
60 | {
61 | "success": true,
62 | "data": {
63 | "month": "Nov",
64 | "day": "17",
65 | "zh": "优质的表现始于积极的态度。",
66 | "en": "Quality performance starts with a positive attitude. ",
67 | "pic": "https://staticedu-wps.cache.iciba.com/image/1695961f05f79cb6bf630ce9747a189d.jpg"
68 | }
69 | }
70 | """
71 | e_context["reply"] = reply
72 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
73 | else:
74 | logger.info(f"获取[每日语录]成功")
75 | reply = Reply()
76 | reply.type = ReplyType.TEXT
77 | reply.content = f"获取[每日语录]失败"
78 |
79 | e_context["reply"] = reply
80 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
81 |
82 | except Exception as e:
83 | logger.error("出现错误,获取[每日语录]失败")
84 | reply = Reply()
85 | reply.type = ReplyType.TEXT
86 | reply.content = f'[ERROR]\n获取[每日语录]失败!\n{e}'
87 | e_context["reply"] = reply
88 | e_context.action = EventAction.BREAK_PASS
89 |
90 | def get_help_text(self, **kwargs):
91 | help_text = "关键词【每日语录】By XcNGG"
92 | return help_text
--------------------------------------------------------------------------------
/已废弃/SearchICP/SearchICP.py:
--------------------------------------------------------------------------------
1 | # encoding:utf-8
2 | import json
3 | import os
4 | import requests
5 | import plugins
6 | from bridge.context import ContextType
7 | from bridge.reply import Reply, ReplyType
8 | from common.log import logger
9 | from plugins import *
10 |
11 | @plugins.register(
12 | # name="SearchICP",
13 | name="域名查询",
14 | desire_priority=0,
15 | # namecn="备案查询",
16 | desc="输入关键词(注意小写)'icp baidu.com'即可查询ICP哦-By XcNGG",
17 | version="1.2",
18 | author="XcNGG",
19 | )
20 | class SearchICP(Plugin):
21 | def __init__(self):
22 | super().__init__()
23 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
24 | logger.info("[SearchICP-XcNGG] inited.")
25 | self.headers = {
26 |
27 | }
28 |
29 | def on_handle_context(self, e_context: EventContext):
30 | content = e_context["context"].content # 获取事件上下文中的消息内容
31 | try:
32 | if content.startswith("icp "):
33 | domain = content.split(' ')[-1]
34 | headers = {
35 | "authority": "api.uutool.cn",
36 | "accept": "application/json, text/javascript, */*; q=0.01",
37 | "accept-language": "zh-CN,zh;q=0.9",
38 | "cache-control": "no-cache",
39 | "origin": "https://uutool.cn",
40 | "pragma": "no-cache",
41 | "referer": "https://uutool.cn/",
42 | "sec-ch-ua": "^\\^Google",
43 | "sec-ch-ua-mobile": "?0",
44 | "sec-ch-ua-platform": "^\\^Windows^^",
45 | "sec-fetch-dest": "empty",
46 | "sec-fetch-mode": "cors",
47 | "sec-fetch-site": "same-site",
48 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
49 | }
50 | url = "https://api.uutool.cn/beian/icp/"
51 | data = {
52 | "domain": domain
53 | }
54 |
55 | response = requests.post(url, headers=headers, data=data).json()
56 |
57 | status = response.get('status',0)
58 |
59 | if status == 1:
60 | logger.info(f"查询icp {domain} 成功")
61 | reply = Reply()
62 | reply.type = ReplyType.TEXT
63 | reply.content = f"【🔎域名: {domain}】\n"
64 | # {'status': 1,
65 | # 'data':
66 | # {'domain': 'baidu.com',
67 | # 'is_icp': 1,
68 | # 'icp_org': '北京百度网讯科技有限公司',
69 | # 'icp_no': '京ICP证030173号-1'
70 | # },
71 | # 'req_id': 'e29115d357a76b547871'}
72 | reply.content += f"【是否备案】:{response.get('data','未知').get('is_icp','未知')}\n"
73 | reply.content += f"【所属机构/个人】:{response.get('data','未知').get('icp_org','未知')}\n"
74 | reply.content += f"【备案号】:{response.get('data','未知').get('icp_no','未知')}\n"
75 | reply.content += f"【梯子信息】:{self.is_extranet(domain)}\n"
76 | reply.content += f"【注册信息】:{self.can_register(domain)}"
77 | e_context["reply"] = reply
78 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
79 | else:
80 | logger.info(f"查询icp {domain} 失败")
81 | reply = Reply()
82 | reply.type = ReplyType.TEXT
83 | reply.content = f"【🔎域名: {domain}】查询失败!"
84 | e_context["reply"] = reply
85 | e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑
86 |
87 | except Exception as e:
88 | logger.error("出现错误,查询ICP失败!")
89 | reply = Reply()
90 | reply.type = ReplyType.TEXT
91 | reply.content = f'[ERROR]\n查询ICP失败!\n{e}'
92 | e_context["reply"] = reply
93 | e_context.action = EventAction.BREAK_PASS
94 |
95 |
96 | def is_extranet(self,domain):
97 | """
98 | 查看域名是否被墙
99 | {"success":true,"domain":"google.com","msg":"被墙了"}
100 | """
101 | url = "https://api.vvhan.com/api/qiang?url=" + domain
102 | headers = {
103 | "authority": "api.vvhan.com",
104 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
105 | "accept-language": "zh-CN,zh;q=0.9",
106 | "cache-control": "no-cache",
107 | "pragma": "no-cache",
108 | "sec-ch-ua": "^\\^Google",
109 | "sec-ch-ua-mobile": "?0",
110 | "sec-ch-ua-platform": "^\\^Windows^^",
111 | "sec-fetch-dest": "document",
112 | "sec-fetch-mode": "navigate",
113 | "sec-fetch-site": "none",
114 | "sec-fetch-user": "?1",
115 | "upgrade-insecure-requests": "1",
116 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
117 | }
118 | try:
119 | response = requests.get(url=url,headers=headers).json()
120 | if response.get('success',False):
121 | return response.get('msg')
122 | else:
123 | return '获取失败'
124 | except Exception as e:
125 | return f'[ERROR] {e}'
126 |
127 | def can_register(self, domain):
128 | """
129 | 查看域名是否可以注册
130 | {"success":true,"domain":"google.com","message":"不可注册"}
131 | """
132 | url = "https://api.vvhan.com/api/dm"
133 | params = {
134 | "url": domain
135 | }
136 | headers = {
137 | "authority": "api.vvhan.com",
138 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
139 | "accept-language": "zh-CN,zh;q=0.9",
140 | "cache-control": "no-cache",
141 | "pragma": "no-cache",
142 | "sec-ch-ua": "^\\^Google",
143 | "sec-ch-ua-mobile": "?0",
144 | "sec-ch-ua-platform": "^\\^Windows^^",
145 | "sec-fetch-dest": "document",
146 | "sec-fetch-mode": "navigate",
147 | "sec-fetch-site": "none",
148 | "sec-fetch-user": "?1",
149 | "upgrade-insecure-requests": "1",
150 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
151 | }
152 | try:
153 | response = requests.get(url=url, headers=headers,params=params).json()
154 | if response.get('success', False):
155 | return response.get('message')
156 | else:
157 | return '获取失败'
158 | except Exception as e:
159 | return f'[ERROR] {e}'
160 |
161 |
162 |
163 |
164 | def get_help_text(self, **kwargs):
165 | help_text = "关键词【icp baidu.com】(注意小写)By XcNGG"
166 | return help_text
--------------------------------------------------------------------------------
/PerpetualCalendar/PerpetualCalendar.py:
--------------------------------------------------------------------------------
1 | import requests # 导入用于发送 HTTP 请求的库
2 | import json # 导入用于处理 JSON 数据的库
3 | import re # 导入用于正则表达式匹配的库
4 | import plugins # 导入自定义的插件模块
5 | from bridge.reply import Reply, ReplyType # 导入用于构建回复消息的类
6 | from plugins import * # 导入其他自定义插件
7 | from config import conf # 导入配置文件
8 | from datetime import datetime
9 |
10 |
11 | @plugins.register(
12 | name="万年历", # 插件的名称
13 | desire_priority=1, # 插件的优先级
14 | hidden=False, # 插件是否隐藏
15 | desc="万年历", # 插件的描述
16 | version="1.0", # 插件的版本号
17 | author="XcNGG", # 插件的作者
18 | )
19 | class PerpetualCalendar(Plugin):
20 | def __init__(self):
21 | super().__init__()
22 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
23 | logger.info("[Almanac-XcNGG] inited") # 初始化插件时打印一条消息
24 |
25 | def on_handle_context(self, e_context: EventContext):
26 | content = e_context["context"].content # 获取事件上下文中的消息内容
27 | url = "https://api.songzixian.com/api/perpetual-calendar"
28 | day = datetime.now().strftime("%Y-%m-%d")
29 | """
30 | dataSource 是 string LOCAL_PERPETUAL_CALENDAR
31 | calendarType 是 string (默认)日历类型:值必须为gregorian(阳历)或lunar(阴历)
32 | data 是 string 日期格式:yyyy-MM-dd
33 | """
34 | params = {
35 | "dataSource": "LOCAL_PERPETUAL_CALENDAR",
36 | "calendarType": "gregorian",
37 | "data": day
38 | }
39 | if content == "阳历": # 如果消息内容为 "阳历"
40 | response = requests.get(url=url, params=params).json()
41 | if response.get('code',500) == 200:
42 | """
43 | {'code': 200,
44 | 'data': {'gregorianInfo': {'date': '2023-11-18', 'dayOfWeek': '星期六'},
45 | 'lunarInfo': {'chineseDate': '二〇二三年十月初六',
46 | 'chineseZodiac': '兔',
47 | 'day': 6,
48 | 'leapMonth': False,
49 | 'month': 10,
50 | 'year': 2023},
51 | 'traditionalChineseInfo': {'currentJieQi': '',
52 | 'dayStemBranch': '庚辰日',
53 | 'monthStemBranch': '癸亥月',
54 | 'nextJieQiName': '小雪',
55 | 'nextJieQiTime': '2023-11-22 22:02:29',
56 | 'yearStemBranch': '癸卯年'}},
57 | 'message': '正常响应',
58 | 'requestId': '1725722671976681472'}
59 | """
60 | data = response.get('data')
61 | gregorianInfo = data.get('gregorianInfo')
62 | date = gregorianInfo.get('date')
63 | dayOfWeek = gregorianInfo.get('dayOfWeek')
64 | lunarInfo = data.get('lunarInfo')
65 | chineseDate = lunarInfo.get('chineseDate')
66 | chineseZodiac = lunarInfo.get('chineseZodiac')
67 | traditionalChineseInfo = data.get('traditionalChineseInfo')
68 | currentJieQi = traditionalChineseInfo.get('currentJieQi')
69 | yearStemBranch = traditionalChineseInfo.get('yearStemBranch')
70 | monthStemBranch = traditionalChineseInfo.get('monthStemBranch')
71 | dayStemBranch = traditionalChineseInfo.get('dayStemBranch')
72 | nextJieQiName = traditionalChineseInfo.get('nextJieQiName')
73 | nextJieQiTime = traditionalChineseInfo.get('nextJieQiTime')
74 |
75 | result = f"""📅阳历【{date}】
76 | - {chineseDate} | {dayOfWeek} | {chineseZodiac}年
77 | - {yearStemBranch} · {monthStemBranch} · {dayStemBranch}
78 | - 今日节气:【{currentJieQi}】
79 | - 下个节气:【{nextJieQiTime}】-【{nextJieQiName}】
80 | """
81 | reply = Reply()
82 | reply.type = ReplyType.TEXT
83 | reply.content = result
84 | e_context["reply"] = reply
85 | e_context.action = EventAction.BREAK_PASS
86 |
87 |
88 | # elif content == "阳历": # 如果消息内容为 "阳历"
89 | # response = requests.get(url=url, params=params).json()
90 | # if response.get('code', 500) == 200:
91 | # """
92 | # {'code': 200,
93 | # 'data': {'gregorianInfo': {'date': '2023-12-30', 'dayOfWeek': '星期六'},
94 | # 'lunarInfo': {'chineseDate': '二〇二三年冬月十八',
95 | # 'chineseZodiac': '兔',
96 | # 'day': 18,
97 | # 'leapMonth': False,
98 | # 'month': 11,
99 | # 'year': 2023},
100 | # 'traditionalChineseInfo': {'currentJieQi': '',
101 | # 'dayStemBranch': '壬戌日',
102 | # 'monthStemBranch': '甲子月',
103 | # 'nextJieQiName': '小寒',
104 | # 'nextJieQiTime': '2024-01-06 04:49:09',
105 | # 'yearStemBranch': '癸卯年'}},
106 | # 'message': '正常响应',
107 | # 'requestId': '1725725750474182656'}
108 | # """
109 | # data = response.get('data')
110 | # gregorianInfo = data.get('gregorianInfo')
111 | # date = gregorianInfo.get('date')
112 | # dayOfWeek = gregorianInfo.get('dayOfWeek')
113 | # lunarInfo = data.get('lunarInfo')
114 | # chineseDate = lunarInfo.get('chineseDate')
115 | # chineseZodiac = lunarInfo.get('chineseZodiac')
116 | # traditionalChineseInfo = data.get('traditionalChineseInfo')
117 | # currentJieQi = traditionalChineseInfo.get('currentJieQi')
118 | # yearStemBranch = traditionalChineseInfo.get('yearStemBranch')
119 | # monthStemBranch = traditionalChineseInfo.get('monthStemBranch')
120 | # dayStemBranch = traditionalChineseInfo.get('dayStemBranch')
121 | # nextJieQiName = traditionalChineseInfo.get('nextJieQiName')
122 | # nextJieQiTime = traditionalChineseInfo.get('nextJieQiTime')
123 | #
124 | # result = f"""📅阳历【{date}】
125 | # -{chineseDate}|{dayOfWeek}|{chineseZodiac}年
126 | # - {yearStemBranch} · {monthStemBranch} · {dayStemBranch}
127 | # - 今日节气:{currentJieQi}
128 | # - 下个节气:{nextJieQiName}({nextJieQiTime})
129 | # """
130 | # reply = Reply()
131 | # reply.type = ReplyType.TEXT
132 | # reply.content = result
133 | # e_context["reply"] = reply
134 | # e_context.action = EventAction.BREAK_PASS
135 |
136 |
137 |
138 |
139 | def get_help_text(self, **kwargs):
140 | help_text = "关键词【阳历】By XcNgg"
141 | return help_text
142 |
--------------------------------------------------------------------------------
/VulnerabilityIntelligence/SearchCNNVD.py:
--------------------------------------------------------------------------------
1 | """
2 | CNNVD 漏洞查询
3 | https://www.cnnvd.org.cn/home/loophole
4 | """
5 | import pprint
6 | import requests
7 | import openpyxl
8 | import json
9 | from my_fake_useragent import UserAgent
10 | import os
11 | from bridge.context import ContextType
12 | import hashlib
13 | import time
14 | from common.log import logger
15 | import requests
16 | from bridge.reply import Reply, ReplyType
17 | from plugins import *
18 |
19 | hazardLevel ={
20 | 0:"未知❓",
21 | 1:"超危❗❗❗",
22 | 2:"高危❗❗",
23 | 3:"中危❗",
24 | 4:"低危⚠️"
25 | }
26 |
27 | def search_cnnvd(number,e_context:EventContext):
28 | """
29 | number : CNNVD编号 例如 CNNVD-202311-1534
30 | """
31 | #
32 | content = f"🔍【{number}】\n"
33 | # 最大二次请求条数
34 | max_data = 2
35 | logger.info(f"🔍【{number}】")
36 |
37 | headers = {
38 | "Accept": "application/json, text/plain, */*",
39 | "Accept-Language": "zh-CN,zh;q=0.9",
40 | "Cache-Control": "no-cache",
41 | "Connection": "keep-alive",
42 | "Content-Type": "application/json;charset=UTF-8",
43 | "Origin": "https://www.cnnvd.org.cn",
44 | "Pragma": "no-cache",
45 | "Referer": "https://www.cnnvd.org.cn/home/loophole",
46 | "Sec-Fetch-Dest": "empty",
47 | "Sec-Fetch-Mode": "cors",
48 | "Sec-Fetch-Site": "same-origin",
49 | "User-Agent": UserAgent().random(),
50 | "sec-ch-ua": "^\\^Google",
51 | "sec-ch-ua-mobile": "?0",
52 | "sec-ch-ua-platform": "^\\^Windows^^",
53 | }
54 | url = "https://www.cnnvd.org.cn/web/homePage/cnnvdVulList"
55 | data = '{{"pageIndex":1,"pageSize":{},"keyword":"{}","hazardLevel":"","vulType":"","vendor":"","product":"","dateType":""}}'.format(
56 | max_data, number)
57 |
58 | response = requests.post(url, headers=headers, data=data)
59 | """
60 | {
61 | 'code': 200,
62 | 'data': {'pageIndex': 1,
63 | 'pageSize': 10,
64 | 'records': [{'cnnvdCode': 'CNNVD-202311-1534',
65 | 'createTime': '2023-11-17',
66 | 'cveCode': 'CVE-2023-6178',
67 | 'hazardLevel': 0,
68 | 'id': 'b53f7d7e933e4876b5e8452153719738',
69 | 'publishTime': '2023-11-17',
70 | 'typeName': None,
71 | 'updateTime': '2023-11-19',
72 | 'vulName': 'Nessus 安全漏洞',
73 | 'vulType': '0'}],
74 | 'total': 1},
75 | 'message': '操作成功',
76 | 'success': True,
77 | 'time': '2023-11-20 15:54:26'
78 | }
79 | """
80 | try:
81 | response_data = response.json()
82 | response_status = response_data.get('code',400)
83 | print(response_data)
84 | if response_status == 200:
85 | total = response_data.get('data').get('total')
86 | print(f"总共{total}条")
87 | logger.info(f" (共查询到{total}条漏洞信息)")
88 | # 如果条数为0
89 | if total == 0:
90 | content += "未查询到相关漏洞信息"
91 |
92 | # 如果条数小于等于设定的max_data
93 | elif total <= max_data:
94 | content += f" (共查询到{total}条漏洞信息)\n"
95 | records = response_data.get('data').get('records')
96 | for record in records:
97 | loophole_id = record.get('id')
98 | cnnvd_code = record.get('cnnvdCode')
99 | content += get_loophole(loophole_id,cnnvd_code=cnnvd_code)
100 |
101 | # 如果条数大于设定的max_data
102 | # 则发送Excel
103 | elif total > max_data:
104 | _send_info(e_context=e_context,content=f"🔍【{number}】相关信息共{total}条,已整理为Excel概览")
105 | frequency = total // 50
106 | frequency = 1 if frequency == 0 else frequency
107 |
108 | print(f"需要请求{frequency}次")
109 | result_data = []
110 | for page in range(1,frequency+1):
111 | print(f"第{page}次请求")
112 | url = "https://www.cnnvd.org.cn/web/homePage/cnnvdVulList"
113 | data = '{{"pageIndex":{},"pageSize":{},"keyword":"{}","hazardLevel":"","vulType":"","vendor":"","product":"","dateType":""}}'.format(
114 | page,50, number)
115 | result_data += requests.post(url, headers=headers, data=data).json().get('data').get('records')
116 | file_path = "tmp"
117 |
118 | if not os.path.exists(file_path):
119 | os.makedirs(file_path)
120 |
121 | file_name = hashlib.md5(str(time.time()).encode()).hexdigest() + ".xlsx"
122 | file_path = os.path.join(file_path, file_name)
123 |
124 | print(file_path)
125 | # 创建一个新的工作簿
126 | workbook = openpyxl.Workbook()
127 | # 选择默认的工作表
128 | sheet = workbook.active
129 | sheet.append(['漏洞编号','漏洞等级','漏洞名称','收录时间','更新时间','查询id',])
130 |
131 | print(len(result_data))
132 | for record in result_data:
133 | data = [
134 | record.get('cnnvdCode'),
135 | hazardLevel[record.get('hazardLevel')],
136 | record.get('vulName'),
137 | record.get('createTime'),
138 | record.get('updateTime'),
139 | record.get('id'),
140 | ]
141 | print(data)
142 | sheet.append(data)
143 | sheet.append([])
144 | sheet.append([f"信息量大于{max_data}条"])
145 | sheet.append([f"已自动为您生成【{number}】相关简报"])
146 | # 保存工作簿
147 | workbook.save(file_path)
148 | reply = Reply()
149 | # 发送文件
150 | reply.type = ReplyType.FILE
151 | reply.content = file_path
152 | logger.info(f"查询结果:{file_path}")
153 | e_context["reply"] = reply
154 | e_context.action = EventAction.BREAK_PASS
155 | # 返回:暂时无用
156 | return file_path,reply
157 |
158 | except Exception as e:
159 | print(e)
160 | logger.info(f"查询漏洞发生错误:{e}")
161 | content += f"发生错误:{e}\n"
162 |
163 | reply = Reply()
164 | reply.type = ReplyType.TEXT
165 | reply.content = content
166 | logger.info(reply.content)
167 | e_context["reply"] = reply
168 | e_context.action = EventAction.BREAK_PASS
169 | # 返回:暂时无用
170 | return content
171 |
172 | # 进一步查询漏洞详细信息
173 | def get_loophole(loophole_id,cnnvd_code="CNNVD-202311-299"):
174 | content = ""
175 | headers = {
176 | "Accept": "application/json, text/plain, */*",
177 | "Accept-Language": "zh-CN,zh;q=0.9",
178 | "Cache-Control": "no-cache",
179 | "Connection": "keep-alive",
180 | "Content-Type": "application/json;charset=UTF-8",
181 | "Origin": "https://www.cnnvd.org.cn",
182 | "Pragma": "no-cache",
183 | "Referer": "https://www.cnnvd.org.cn/home/loophole",
184 | "Sec-Fetch-Dest": "empty",
185 | "Sec-Fetch-Mode": "cors",
186 | "Sec-Fetch-Site": "same-origin",
187 | "User-Agent": UserAgent().random(),
188 | "sec-ch-ua": "^\\^Google",
189 | "sec-ch-ua-mobile": "?0",
190 | "sec-ch-ua-platform": "^\\^Windows^^",
191 | }
192 | url = "https://www.cnnvd.org.cn/web/cnnvdVul/getCnnnvdDetailOnDatasource"
193 | data = '{"id":"%s","vulType":"0","cnnvdCode":"%s"}' % (loophole_id,cnnvd_code)
194 | # response_data = requests.post(url=url, headers=headers, data=data).text
195 | # print(response_data)
196 | response_data = requests.post(url=url, headers=headers, data=data).json().get('data').get('cnnvdDetail')
197 | content += f"【漏洞名称】{response_data.get('vulName')}\n"
198 | content += f"【漏洞等级】{hazardLevel[response_data.get('hazardLevel')]}\n"
199 | content += f"【CNNVD编号】{response_data.get('cnnvdCode')}\n"
200 | content += f"【CVE编号】{response_data.get('cveCode')}\n"
201 | content += f"【CVE】{response_data.get('cveCode')}\n"
202 | content += f"【漏洞类型】{response_data.get('vulType')}\n"
203 | content += f"【漏洞描述】{response_data.get('vulDesc')}\n"
204 | content += f"【收录时间】{response_data.get('publishTime')}\n"
205 | content += f"【更新时间】\n{response_data.get('updateTime')}\n"
206 | content += f"【官方补丁】{response_data.get('patch')}\n"
207 | content += f"【参考网址】\n{response_data.get('referUrl')}\n"
208 | content += f"----------\n"
209 | """
210 | {'code': 200,
211 | 'data': {'cnnvdDetail': {'affectedProduct': None,
212 | 'affectedSystem': None,
213 | 'affectedVendor': 'Subrion',
214 | 'cnnvdCode': 'CNNVD-202311-299',
215 | 'cnnvdFiledShow': 'vul_name,cnnvd_code,_code,publish_time,is_official,vendor,hazard_level,vul_type,vul_desc,affected_product,affected_vendor,product_desc,affected_system,refer_url,patch_id,product,update_time,patch',
216 | 'createTime': None,
217 | 'createUid': None,
218 | 'createUname': None,
219 | 'cveCode': 'CVE-2023-46947',
220 | 'cveFiledShow': None,
221 | 'cveVulVO': None,
222 | 'deleted': None,
223 | 'hazardLevel': 1,
224 | 'huaweiFiledShow': None,
225 | 'huaweiVulVO': None,
226 | 'ibmFiledShow': None,
227 | 'ibmVulVO': None,
228 | 'icsCertFiledShow': None,
229 | 'icsCertVulVO': None,
230 | 'id': None,
231 | 'isOfficial': 0,
232 | 'microsoftFiledShow': None,
233 | 'microsoftVulVO': None,
234 | 'nvdFiledShow': None,
235 | 'nvdVulVO': None,
236 | 'patch': None,
237 | 'patchId': None,
238 | 'productDesc': None,
239 | 'publishTime': '2023-11-03 00:00:00',
240 | 'referUrl': '来源:MISC\r\n'
241 | '链接:https://github.com/intelliants/subrion/issues/909\r\n'
242 | '\r\n'
243 | '来源:cxsecurity.com\r\n'
244 | '链接:https://cxsecurity.com/cveshow/CVE-2023-46947/',
245 | 'updateTime': '2023-11-13 00:00:00',
246 | 'updateUid': None,
247 | 'updateUname': None,
248 | 'varchar1': '其他',
249 | 'vendor': '1005853',
250 | 'version': None,
251 | 'vulDesc': 'Subrion '
252 | 'CMS是Subrion团队的一套基于PHP的内容管理系统(CMS)。该系统可被集成到网站,并支持多种扩展插件等。\r\n'
253 | 'Subrion CMS '
254 | '4.2.1版本存在安全漏洞。攻击者利用该漏洞可以远程执行代码。',
255 | 'vulName': 'Subrion CMS 安全漏洞',
256 | 'vulType': '其他',
257 | 'vulTypeName': '其他'},
258 | 'receviceVulDetail': None},
259 | 'message': '操作成功',
260 | 'success': True,
261 | 'time': '2023-11-20 17:05:15'}
262 |
263 | """
264 | pprint.pprint(response_data)
265 | return content
266 |
267 |
268 |
269 | def _send_info(e_context: EventContext, content: str):
270 | reply = Reply(ReplyType.TEXT, content)
271 | channel = e_context["channel"]
272 | channel.send(reply, e_context["context"])
273 |
274 |
275 | if __name__ == '__main__':
276 | # content = ""
277 | # number = "CNNVD-202311-224"
278 | # result = search_cnnvd(number=number)
279 | # if isinstance(result,str):
280 | # content += result
281 | # print(content)
282 | print(get_loophole(loophole_id="c03637953d3b498f8f0becc3b6989e35"))
283 |
284 |
285 |
--------------------------------------------------------------------------------
/WindowsHostInfo/systemfuc.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | '''
3 | https://blog.csdn.net/qq_26373925/article/details/108047836
4 | '''
5 | import pprint
6 | from typing import List, Dict, Any
7 | import os
8 | import time
9 | import psutil
10 | import platform
11 | import hashlib
12 | import re
13 | import sys
14 | from cachelib import SimpleCache
15 |
16 | cache = SimpleCache()
17 |
18 | UNIX: bool = os.name == 'posix'
19 | SYS: str = platform.system()
20 |
21 | class CpuConstants:
22 | def __init__(self):
23 | '''
24 | 初始化CPU常量(多平台)
25 | Returns
26 | -------
27 | self.
28 |
29 | '''
30 | self.WMI = None
31 | self.initialed: bool = False
32 | self.cpuList: list = [] # windows only
33 |
34 | self.cpuCount: int = 0 # 物理cpu数量
35 | self.cpuCore: int = 0 # cpu物理核心数
36 | self.cpuThreads: int = 0 # cpu逻辑核心数
37 | self.cpuName: str = '' # cpu型号
38 |
39 | self.Update(True)
40 |
41 | def Update(self, update: bool = False) -> None:
42 | '''
43 | 更新cpu数据
44 |
45 | Returns
46 | -------
47 | None.
48 |
49 | '''
50 | if UNIX:
51 | self.GetCpuConstantsUnix(update)
52 | else:
53 | self.GetCpuConstantsWindows(update)
54 |
55 | self.initialed: bool = True
56 |
57 | @property
58 | def getDict(self) -> Dict[int, str]:
59 | '''
60 | 以字典格式获取当前cpu常量
61 |
62 | Returns
63 | -------
64 | Dict[int, str]
65 | DESCRIPTION.
66 |
67 | '''
68 | if not self.initialed: self.Update()
69 | return {
70 | 'cpu_count': self.cpuCount,
71 | 'cpu_name': self.cpuName,
72 | 'cpu_core': self.cpuCore,
73 | 'cpu_threads': self.cpuThreads
74 | }
75 |
76 | def GetCpuConstantsUnix(self, update: bool = False) -> None:
77 | '''
78 | 获取unix下的cpu信息
79 |
80 | Parameters
81 | ----------
82 | update : bool, optional
83 | DESCRIPTION. The default is False.
84 |
85 | Returns
86 | -------
87 | None
88 | DESCRIPTION.
89 |
90 | '''
91 | if update or not self.initialed:
92 | ids: list = re.findall("physical id.+", readFile('/proc/cpuinfo'))
93 |
94 | # 物理cpu个数
95 | self.cpuCount: int = len(set(ids))
96 |
97 | # cpu型号(名称)
98 | self.cpuName: str = self.getCpuTypeUnix()
99 |
100 | self.GetCpuConstantsBoth()
101 |
102 | def InitWmi(self) -> None:
103 | '''
104 | 初始化wmi(for windows)
105 |
106 | Returns
107 | -------
108 | None
109 | DESCRIPTION.
110 |
111 | '''
112 | import wmi
113 | self.WMI = wmi.WMI()
114 |
115 | def GetCpuConstantsBoth(self, update: bool = False) -> None:
116 | '''
117 | 获取多平台共用的cpu信息
118 |
119 | Parameters
120 | ----------
121 | update : bool, optional
122 | 强制更新数据. The default is False.
123 |
124 | Returns
125 | -------
126 | None
127 | DESCRIPTION.
128 |
129 | '''
130 | if update or not self.initialed:
131 | # cpu逻辑核心数
132 | self.cpuThreads: int = psutil.cpu_count()
133 |
134 | # cpu物理核心数
135 | self.cpuCore: int = psutil.cpu_count(logical=False)
136 |
137 | def GetCpuConstantsWindows(self, update: bool = False) -> None:
138 | '''
139 | 获取windows平台的cpu信息
140 |
141 | Parameters
142 | ----------
143 | update : bool, optional
144 | 强制更新数据. The default is False.
145 |
146 | Returns
147 | -------
148 | None
149 | DESCRIPTION.
150 |
151 | '''
152 | if update or not self.initialed:
153 |
154 | # 初始化wmi
155 | if self.WMI == None: self.InitWmi()
156 |
157 | # cpu列表
158 | self.cpuList: list = self.WMI.Win32_Processor()
159 |
160 | # 物理cpu个数
161 | self.cpuCount: int = len(self.cpuList)
162 |
163 | # cpu型号(名称)
164 | self.cpuName: str = self.cpuList[0].Name
165 |
166 | self.GetCpuConstantsBoth()
167 |
168 | @staticmethod
169 | def getCpuTypeUnix() -> str:
170 | '''
171 | 获取CPU型号(unix)
172 |
173 | Returns
174 | -------
175 | str
176 | CPU型号.
177 |
178 | '''
179 | cpuinfo: str = readFile('/proc/cpuinfo')
180 | rep: str = 'model\s+name\s+:\s+(.+)'
181 | tmp = re.search(rep, cpuinfo, re.I)
182 | cpuType: str = ''
183 | if tmp:
184 | cpuType: str = tmp.groups()[0]
185 | else:
186 | cpuinfo = ExecShellUnix('LANG="en_US.UTF-8" && lscpu')[0]
187 | rep = 'Model\s+name:\s+(.+)'
188 | tmp = re.search(rep, cpuinfo, re.I)
189 | if tmp: cpuType = tmp.groups()[0]
190 | return cpuType
191 |
192 |
193 | def GetCpuInfo(interval: int = 1) -> Dict[str, Any]:
194 | '''
195 | 获取CPU信息
196 |
197 | Parameters
198 | ----------
199 | interval : int, optional
200 | DESCRIPTION. The default is 1.
201 |
202 | Returns
203 | -------
204 | Dict[float, list, dict]
205 | DESCRIPTION.
206 |
207 | '''
208 | time.sleep(0.5)
209 |
210 | # cpu总使用率
211 | used: float = psutil.cpu_percent(interval)
212 |
213 | # 每个逻辑cpu使用率
214 | usedList: List[float] = psutil.cpu_percent(percpu=True)
215 |
216 | return {'used': used, 'used_list': usedList, **cpuConstants.getDict}
217 |
218 |
219 | def readFile(filename: str) -> str:
220 | '''
221 | 读取文件内容
222 |
223 | Parameters
224 | ----------
225 | filename : str
226 | 文件名.
227 |
228 | Returns
229 | -------
230 | str
231 | 文件内容.
232 |
233 | '''
234 | try:
235 | with open(filename, 'r', encoding='utf-8') as file:
236 | return file.read()
237 | except:
238 | pass
239 |
240 | return ''
241 |
242 |
243 | def GetLoadAverage() -> dict:
244 | '''
245 | 获取服务器负载状态(多平台)
246 |
247 | Returns
248 | -------
249 | dict
250 | DESCRIPTION.
251 |
252 | '''
253 | try:
254 | c: list = os.getloadavg()
255 | except:
256 | c: list = [0, 0, 0]
257 | data: dict = {i: c[idx] for idx, i in enumerate(('one', 'five', 'fifteen'))}
258 | data['max'] = psutil.cpu_count() * 2
259 | data['limit'] = data['max']
260 | data['safe'] = data['max'] * 0.75
261 | return data
262 |
263 |
264 | def GetMemInfo() -> dict:
265 | '''
266 | 获取内存信息(多平台)
267 |
268 | Returns
269 | -------
270 | dict
271 | DESCRIPTION.
272 |
273 | '''
274 | if UNIX: return GetMemInfoUnix()
275 | return GetMemInfoWindows()
276 |
277 |
278 | def GetMemInfoUnix() -> Dict[str, int]:
279 | '''
280 | 获取内存信息(unix)
281 |
282 | Returns
283 | -------
284 | dict
285 | DESCRIPTION.
286 |
287 | '''
288 | mem = psutil.virtual_memory()
289 | memInfo: dict = {
290 | 'memTotal': ToSizeInt(mem.total, 'MB'),
291 | 'memFree': ToSizeInt(mem.free, 'MB'),
292 | 'memBuffers': ToSizeInt(mem.buffers, 'MB'),
293 | 'memCached': ToSizeInt(mem.cached, 'MB'),
294 | }
295 | memInfo['memRealUsed'] = \
296 | memInfo['memTotal'] - \
297 | memInfo['memFree'] - \
298 | memInfo['memBuffers'] - \
299 | memInfo['memCached']
300 |
301 | memInfo['memUsedPercent'] = memInfo['memRealUsed'] / memInfo['memTotal'] * 100
302 |
303 | return memInfo
304 |
305 |
306 | def GetMemInfoWindows() -> dict:
307 | '''
308 | 获取内存信息(windows)
309 |
310 | Returns
311 | -------
312 | dict
313 | DESCRIPTION.
314 |
315 | '''
316 | mem = psutil.virtual_memory()
317 | memInfo: dict = {
318 | 'memTotal': ToSizeInt(mem.total, 'MB'),
319 | 'memFree': ToSizeInt(mem.free, 'MB'),
320 | 'memRealUsed': ToSizeInt(mem.used, 'MB'),
321 | 'menUsedPercent': mem.used / mem.total * 100
322 | }
323 |
324 | return memInfo
325 |
326 |
327 | def ToSizeInt(byte: int, target: str) -> int:
328 | '''
329 | 将字节大小转换为目标单位的大小
330 |
331 | Parameters
332 | ----------
333 | byte : int
334 | int格式的字节大小(bytes size)
335 | target : str
336 | 目标单位,str.
337 |
338 | Returns
339 | -------
340 | int
341 | 转换为目标单位后的字节大小.
342 |
343 | '''
344 | return int(byte / 1024 ** (('KB', 'MB', 'GB', 'TB').index(target) + 1))
345 |
346 |
347 | def ToSizeString(byte: int) -> str:
348 | '''
349 | 获取字节大小字符串
350 |
351 | Parameters
352 | ----------
353 | byte : int
354 | int格式的字节大小(bytes size).
355 |
356 | Returns
357 | -------
358 | str
359 | 自动转换后的大小字符串,如:6.90 GB.
360 |
361 | '''
362 | units: tuple = ('b', 'KB', 'MB', 'GB', 'TB')
363 | re = lambda: '{:.2f} {}'.format(byte, u)
364 | for u in units:
365 | if byte < 1024: return re()
366 | byte /= 1024
367 | return re()
368 |
369 |
370 | def GetDiskInfo() -> list:
371 | '''
372 | 获取磁盘信息(多平台)
373 |
374 | Returns
375 | -------
376 | list
377 | 列表.
378 |
379 | '''
380 | try:
381 | if UNIX: return GetDiskInfoUnix()
382 | return GetDiskInfoWindows()
383 | except Exception as err:
384 | print('获取磁盘信息异常(unix: {}):'.format(UNIX), err)
385 | return []
386 |
387 |
388 | def GetDiskInfoWindows() -> list:
389 | '''
390 | 获取磁盘信息Windows
391 |
392 | Returns
393 | -------
394 | diskInfo : list
395 | 列表.
396 |
397 | '''
398 | diskIo: list = psutil.disk_partitions()
399 | diskInfo: list = []
400 | for disk in diskIo:
401 | tmp: dict = {}
402 | try:
403 | tmp['path'] = disk.mountpoint.replace("\\", "/")
404 | usage = psutil.disk_usage(disk.mountpoint)
405 | tmp['size'] = {
406 | 'total': usage.total,
407 | 'used': usage.used,
408 | 'free': usage.free,
409 | 'percent': usage.percent
410 | }
411 | tmp['fstype'] = disk.fstype
412 | tmp['inodes'] = False
413 | diskInfo.append(tmp)
414 | except:
415 | pass
416 | return diskInfo
417 |
418 |
419 | def GetDiskInfoUnix() -> list:
420 | '''
421 | 获取硬盘分区信息(unix)
422 |
423 | Returns
424 | -------
425 | list
426 | DESCRIPTION.
427 |
428 | '''
429 | temp: list = (
430 | ExecShellUnix("df -h -P|grep '/'|grep -v tmpfs")[0]).split('\n')
431 | tempInodes: list = (
432 | ExecShellUnix("df -i -P|grep '/'|grep -v tmpfs")[0]).split('\n')
433 | diskInfo: list = []
434 | n: int = 0
435 | cuts: list = [
436 | '/mnt/cdrom',
437 | '/boot',
438 | '/boot/efi',
439 | '/dev',
440 | '/dev/shm',
441 | '/run/lock',
442 | '/run',
443 | '/run/shm',
444 | '/run/user'
445 | ]
446 | for tmp in temp:
447 | n += 1
448 | try:
449 | inodes: list = tempInodes[n - 1].split()
450 | disk: list = tmp.split()
451 | if len(disk) < 5: continue
452 | if disk[1].find('M') != -1: continue
453 | if disk[1].find('K') != -1: continue
454 | if len(disk[5].split('/')) > 10: continue
455 | if disk[5] in cuts: continue
456 | if disk[5].find('docker') != -1: continue
457 | arr = {}
458 | arr['path'] = disk[5]
459 | tmp1 = [disk[1], disk[2], disk[3], disk[4]]
460 | arr['size'] = tmp1
461 | arr['inodes'] = [inodes[1], inodes[2], inodes[3], inodes[4]]
462 | diskInfo.append(arr)
463 | except Exception as ex:
464 | print('信息获取错误:', str(ex))
465 | continue
466 | return diskInfo
467 |
468 |
469 | def md5(strings: str) -> str:
470 | '''
471 | 生成md5
472 |
473 | Parameters
474 | ----------
475 | strings : TYPE
476 | 要进行hash处理的字符串
477 |
478 | Returns
479 | -------
480 | str[32]
481 | hash后的字符串.
482 |
483 | '''
484 |
485 | m = hashlib.md5()
486 | m.update(strings.encode('utf-8'))
487 | return m.hexdigest()
488 |
489 |
490 | def GetErrorInfo() -> str:
491 | '''
492 | 获取traceback中的错误
493 |
494 | Returns
495 | -------
496 | str
497 | DESCRIPTION.
498 |
499 | '''
500 | import traceback
501 | errorMsg = traceback.format_exc()
502 | return errorMsg
503 |
504 |
505 | def ExecShellUnix(cmdstring: str, shell=True):
506 | '''
507 | 执行Shell命令(Unix)
508 |
509 | Parameters
510 | ----------
511 | cmdstring : str
512 | DESCRIPTION.
513 | shell : TYPE, optional
514 | DESCRIPTION. The default is True.
515 |
516 | Returns
517 | -------
518 | a : TYPE
519 | DESCRIPTION.
520 | e : TYPE
521 | DESCRIPTION.
522 |
523 | '''
524 | a: str = ''
525 | e: str = ''
526 | import subprocess, tempfile
527 |
528 | try:
529 | rx: str = md5(cmdstring)
530 | succ_f = tempfile.SpooledTemporaryFile(
531 | max_size=4096,
532 | mode='wb+',
533 | suffix='_succ',
534 | prefix='btex_' + rx,
535 | dir='/dev/shm'
536 | )
537 | err_f = tempfile.SpooledTemporaryFile(
538 | max_size=4096,
539 | mode='wb+',
540 | suffix='_err',
541 | prefix='btex_' + rx,
542 | dir='/dev/shm'
543 | )
544 | sub = subprocess.Popen(
545 | cmdstring,
546 | close_fds=True,
547 | shell=shell,
548 | bufsize=128,
549 | stdout=succ_f,
550 | stderr=err_f
551 | )
552 | sub.wait()
553 | err_f.seek(0)
554 | succ_f.seek(0)
555 | a = succ_f.read()
556 | e = err_f.read()
557 | if not err_f.closed: err_f.close()
558 | if not succ_f.closed: succ_f.close()
559 | except Exception as err:
560 | print(err)
561 | try:
562 | if type(a) == bytes: a = a.decode('utf-8')
563 | if type(e) == bytes: e = e.decode('utf-8')
564 | except Exception as err:
565 | print(err)
566 |
567 | return a, e
568 |
569 |
570 | def GetNetWork() -> dict:
571 | '''
572 | 获取系统网络信息
573 |
574 | Returns
575 | -------
576 | dict
577 | DESCRIPTION.
578 |
579 | '''
580 | networkIo: list = [0, 0, 0, 0]
581 | cache_timeout: int = 86400
582 | try:
583 | networkIo = psutil.net_io_counters()[:4]
584 | except:
585 | pass
586 |
587 | otime = cache.get("otime")
588 | if not otime:
589 | otime = time.time()
590 | cache.set('up', networkIo[0], cache_timeout)
591 | cache.set('down', networkIo[1], cache_timeout)
592 | cache.set('otime', otime, cache_timeout)
593 |
594 | ntime = time.time()
595 | networkInfo: dict = {'up': 0, 'down': 0}
596 | networkInfo['upTotal'] = networkIo[0]
597 | networkInfo['downTotal'] = networkIo[1]
598 | try:
599 | networkInfo['up'] = round(
600 | float(networkIo[0] - cache.get("up")) / 1024 / (ntime - otime),
601 | 2
602 | )
603 | networkInfo['down'] = round(
604 | float(networkIo[1] - cache.get("down")) / 1024 / (ntime - otime),
605 | 2
606 | )
607 | except:
608 | pass
609 |
610 | networkInfo['downPackets'] = networkIo[3]
611 | networkInfo['upPackets'] = networkIo[2]
612 |
613 | cache.set('up', networkIo[0], cache_timeout)
614 | cache.set('down', networkIo[1], cache_timeout)
615 | cache.set('otime', time.time(), cache_timeout)
616 |
617 | return networkInfo
618 |
619 |
620 | def GetSystemInfo() -> dict:
621 | systemInfo: dict = {}
622 | systemInfo['cpu'] = GetCpuInfo()
623 | systemInfo['load'] = GetLoadAverage()
624 | systemInfo['mem'] = GetMemInfo()
625 | systemInfo['disk'] = GetDiskInfo()
626 |
627 | return systemInfo
628 |
629 |
630 | def GetIoReadWrite() -> Dict[str, int]:
631 | '''
632 | 获取系统IO读写
633 |
634 | Returns
635 | -------
636 | dict
637 | DESCRIPTION.
638 |
639 | '''
640 | ioDisk = psutil.disk_io_counters()
641 | ioTotal: dict = {}
642 | ioTotal['write'] = GetIoWrite(ioDisk.write_bytes)
643 | ioTotal['read'] = GetIoRead(ioDisk.read_bytes)
644 | return ioTotal
645 |
646 |
647 | def GetIoWrite(ioWrite: int) -> int:
648 | '''
649 | 获取IO写
650 |
651 | Parameters
652 | ----------
653 | ioWrite : TYPE
654 | DESCRIPTION.
655 |
656 | Returns
657 | -------
658 | int
659 | DESCRIPTION.
660 |
661 | '''
662 | diskWrite: int = 0
663 | oldWrite: int = cache.get('io_write')
664 | if not oldWrite:
665 | cache.set('io_write', ioWrite)
666 | return diskWrite;
667 |
668 | oldTime: float = cache.get('io_time')
669 | newTime: float = time.time()
670 | if not oldTime: oldTime = newTime
671 | ioEnd: int = (ioWrite - oldWrite)
672 | timeEnd: float = (time.time() - oldTime)
673 | if ioEnd > 0:
674 | if timeEnd < 1: timeEnd = 1
675 | diskWrite = ioEnd / timeEnd
676 | cache.set('io_write', ioWrite)
677 | cache.set('io_time', newTime)
678 | if diskWrite > 0: return int(diskWrite)
679 | return 0
680 |
681 |
682 | def GetIoRead(ioRead):
683 | '''
684 | 读取IO读
685 |
686 | Parameters
687 | ----------
688 | ioRead : TYPE
689 | DESCRIPTION.
690 |
691 | Returns
692 | -------
693 | TYPE
694 | DESCRIPTION.
695 |
696 | '''
697 | diskRead: int = 0
698 | oldRead: int = cache.get('io_read')
699 | if not oldRead:
700 | cache.set('io_read', ioRead)
701 | return diskRead;
702 | oldTime: float = cache.get('io_time')
703 | newTime: float = time.time()
704 | if not oldTime: oldTime = newTime
705 | ioEnd: int = (ioRead - oldRead)
706 | timeEnd: float = (time.time() - oldTime)
707 | if ioEnd > 0:
708 | if timeEnd < 1: timeEnd = 1;
709 | diskRead = ioEnd / timeEnd;
710 | cache.set('io_read', ioRead)
711 | if diskRead > 0: return int(diskRead)
712 | return 0
713 |
714 |
715 | def GetRegValue(key: str, subkey: str, value: str) -> Any:
716 | '''
717 | 获取系统注册表信息
718 |
719 | Parameters
720 | ----------
721 | key : str
722 | 类型.
723 | subkey : str
724 | 路径.
725 | value : str
726 | key.
727 |
728 | Returns
729 | -------
730 | value : Any
731 | DESCRIPTION.
732 |
733 | '''
734 | import winreg
735 | key = getattr(winreg, key)
736 | handle = winreg.OpenKey(key, subkey)
737 | (value, type) = winreg.QueryValueEx(handle, value)
738 | return value
739 |
740 |
741 | def GetSystemVersion() -> str:
742 | '''
743 | 获取操作系统版本(多平台)
744 |
745 | Returns
746 | -------
747 | str
748 | DESCRIPTION.
749 |
750 | '''
751 | if UNIX: return GetSystemVersionUnix()
752 | return GetSystemVersionWindows()
753 |
754 |
755 | def GetSystemVersionWindows() -> str:
756 | '''
757 | 获取操作系统版本(windows)
758 |
759 | Returns
760 | -------
761 | str
762 | DESCRIPTION.
763 |
764 | '''
765 | try:
766 | import platform
767 | bit: str = 'x86';
768 | if 'PROGRAMFILES(X86)' in os.environ: bit = 'x64'
769 |
770 | def get(key: str):
771 | return GetRegValue(
772 | "HKEY_LOCAL_MACHINE",
773 | "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
774 | key
775 | )
776 |
777 | osName = get('ProductName')
778 | build = get('CurrentBuildNumber')
779 |
780 | version: str = '{} (build {}) {} (Py{})'.format(
781 | osName, build, bit, platform.python_version())
782 | return version
783 | except Exception as ex:
784 | print('获取系统版本失败,错误:' + str(ex))
785 | return '未知系统版本.'
786 |
787 |
788 | def GetSystemVersionUnix() -> str:
789 | '''
790 | 获取系统版本(unix)
791 |
792 | Returns
793 | -------
794 | str
795 | 系统版本.
796 |
797 | '''
798 | try:
799 | version: str = readFile('/etc/redhat-release')
800 | if not version:
801 | version = readFile(
802 | '/etc/issue'
803 | ).strip().split("\n")[0].replace('\\n', '').replace('\l', '').strip()
804 | else:
805 | version = version.replace(
806 | 'release ', ''
807 | ).replace('Linux', '').replace('(Core)', '').strip()
808 | v = sys.version_info
809 | return version + '(Py {}.{}.{})'.format(v.major, v.minor, v.micro)
810 | except Exception as err:
811 | print('获取系统版本失败,错误:', err)
812 | return '未知系统版本.'
813 |
814 |
815 | def GetBootTime() -> dict:
816 | '''
817 | 获取当前系统启动时间
818 |
819 | Returns
820 | -------
821 | dict
822 | DESCRIPTION.
823 |
824 | '''
825 | bootTime: float = psutil.boot_time()
826 | return {
827 | 'timestamp': bootTime,
828 | 'runtime': time.time() - bootTime,
829 | 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
830 | }
831 |
832 |
833 | def GetCpuConstants() -> dict:
834 | '''
835 | 获取CPU常量信息
836 |
837 | Parameters
838 | ----------
839 | cpuConstants : CpuConstants
840 | DESCRIPTION.
841 |
842 | Returns
843 | -------
844 | dict
845 | DESCRIPTION.
846 |
847 | '''
848 | return cpuConstants.getDict
849 |
850 |
851 | def GetFullSystemData() -> dict:
852 | '''
853 | 获取完全的系统信息
854 |
855 | Returns
856 | -------
857 | dict
858 | DESCRIPTION.
859 |
860 | '''
861 | systemData: dict = {
862 | **GetSystemInfo(),
863 | 'network': {**GetNetWork()},
864 | 'io': {**GetIoReadWrite()},
865 | 'boot': {**GetBootTime()},
866 | 'time': time.time()
867 | }
868 | return systemData
869 |
870 | cpuConstants = CpuConstants()
871 |
872 | if __name__ == '__main__':
873 | """
874 | {'boot': {'datetime': '2023-11-18 09:26:43',
875 | 'runtime': 5699.0,
876 | 'timestamp': 1700265104.9372725},
877 | 'cpu': {'cpu_core': 12,
878 | 'cpu_count': 1,
879 | 'cpu_name': '12th Gen Intel(R) Core(TM) i7-12700',
880 | 'cpu_threads': 20,
881 | 'used': 2.1,
882 | 'used_list': [6.5,
883 | 0.0,
884 | 1.8,
885 | 0.0,
886 | 0.0,
887 | 0.0,
888 | 0.0,
889 | 0.0,
890 | 0.0,
891 | 32.0,
892 | 0.0,
893 | 0.0,
894 | 5.3,
895 | 0.0,
896 | 1.2,
897 | 0.0,
898 | 0.0,
899 | 0.6,
900 | 0.0,
901 | 0.0]},
902 | 'disk': [{'fstype': 'NTFS',
903 | 'inodes': False,
904 | 'path': 'C:/',
905 | 'size': {'free': 249244504064,
906 | 'percent': 37.2,
907 | 'total': 396627013632,
908 | 'used': 147382509568}},
909 | {'fstype': 'NTFS',
910 | 'inodes': False,
911 | 'path': 'D:/',
912 | 'size': {'free': 426563883008,
913 | 'percent': 7.0,
914 | 'total': 458852823040,
915 | 'used': 32288940032}},
916 | {'fstype': 'NTFS',
917 | 'inodes': False,
918 | 'path': 'E:/',
919 | 'size': {'free': 815650734080,
920 | 'percent': 28.7,
921 | 'total': 1143468425216,
922 | 'used': 327817691136}},
923 | {'fstype': 'NTFS',
924 | 'inodes': False,
925 | 'path': 'F:/',
926 | 'size': {'free': 259544453120,
927 | 'percent': 51.0,
928 | 'total': 529647984640,
929 | 'used': 270103531520}},
930 | {'fstype': 'NTFS',
931 | 'inodes': False,
932 | 'path': 'G:/',
933 | 'size': {'free': 234922532864,
934 | 'percent': 84.0,
935 | 'total': 1470732066816,
936 | 'used': 1235809533952}}],
937 | 'io': {'read': 0, 'write': 0},
938 | 'load': {'fifteen': 0,
939 | 'five': 0,
940 | 'limit': 40,
941 | 'max': 40,
942 | 'one': 0,
943 | 'safe': 30.0},
944 | 'mem': {'memFree': 50842,
945 | 'memRealUsed': 14481,
946 | 'memTotal': 65323,
947 | 'menUsedPercent': 22.169209784660683},
948 | 'network': {'down': 0,
949 | 'downPackets': 1015725,
950 | 'downTotal': 1172768471,
951 | 'up': 0,
952 | 'upPackets': 397425,
953 | 'upTotal': 44580225},
954 | 'time': 1700270803.9372725}
955 | """
956 | system_data = GetFullSystemData()
957 | pprint.pprint(system_data)
958 | result = f"""【主机时间】:{system_data['boot']['datetime']}
959 | 【主机系统】:{GetSystemVersion()}
960 | 【CPU信息】:{system_data['cpu']['cpu_name']}
961 | 【CPU占用】:{str(system_data['cpu']['used']*10)+'%'}
962 | 【内存占用】:{str(round(system_data['mem']['menUsedPercent'],1))+'%'}
963 | 【持续运行】:{round(system_data['boot']['runtime'] / 3600,2)} 小时
964 | 【磁盘占用】:
965 | """
966 | disk_info = system_data['disk']
967 | for disk in disk_info:
968 | info = f" 【{disk['path']}占用】:{str(round(disk['size']['percent'],2))}%\n"
969 | result += info
970 | print(result)
971 | # print(GetCpuConstants())
972 | # print(GetSystemInfo())
973 | # print(GetNetWork())
974 | # print(GetIoReadWrite())
975 |
976 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------