├── .github
└── dependabot.yml
├── .gitignore
├── LICENSE
├── README.md
├── __init__.py
├── _config.yml
├── bot.py
├── bot.py.save
├── config_bot.py
├── doc_assets
├── README.html
├── custom_reply.md
├── evaler.md
├── notifyme.md
├── remotely.md
├── repeater.md
├── signin.md
├── start.md
└── weather.md
├── plugins
├── _googlesearch
│ ├── __init__.py
│ └── data_source.py
├── _sign_in
│ ├── __init__.py
│ ├── execute.py
│ └── greets.py
├── azurlane_buildship_simulator
│ ├── __init__.py
│ ├── constants.py
│ └── simulator.py
├── baidutrend
│ ├── __init__.py
│ └── data_source.py
├── custom_reply
│ ├── __init__.py
│ └── group_data.json
├── evaler
│ ├── __init__.py
│ └── data_source_glot_run.py
├── exec.py
├── gamble
│ ├── __init__.py
│ └── diceroll.py
├── notifyme
│ └── __init__.py
├── personality
│ └── __init__.py
├── remotely
│ └── __init__.py
├── repeater
│ └── __init__.py
├── request_handler.py
├── song
│ ├── __init__.py
│ └── data_source.py
├── test_rp
│ └── __init__.py
├── usage.py
└── weather
│ ├── __init__.py
│ ├── china_city_list_source_amap.py
│ ├── china_city_list_source_amap.txt
│ ├── data_source_amap.py
│ └── data_source_openweather.py
├── requirements.txt
└── utils_bot
├── __init__.py
├── command_ops.py
├── datetime.py
├── logging.py
├── msg_ops.py
├── string_ops.py
└── typing.py
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: pip
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | time: "10:00"
8 | open-pull-requests-limit: 10
9 | ignore:
10 | - dependency-name: aiosqlite
11 | versions:
12 | - 0.16.1
13 |
--------------------------------------------------------------------------------
/.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 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 |
106 | # editor
107 | .vscode/
108 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 cos
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## sendo erika on [NoneBot](https://github.com/richardchien/nonebot)
2 | [](LICENSE) 
3 |
4 | ### Description
5 | I am a QQ group chatting bot based on Coolq, Coolq http api and Nonebot which takes advantages on Python's [asyncio](https://docs.python.org/3/library/asyncio.html) mechanisms thus supporting a high volume of message i/o. I do provide useful plugins extended from Nonebot framework to ensure the bot operates at an acceptable and useable level.
6 | Like what was described on Nonebot, I only run on over Python 3.7+ and CoolQ HTTP plugin v4.7+.
7 |
8 | ### Plugins
9 | I do
10 | * detect keywords from group chats and reply from customized settings
11 | * be controlled from owner directly to send messages
12 | * repeat
13 | * sign in
14 | * notify you to wake up from bed at 6 am
15 | * search weather data and etc
16 |
17 | You can freely only absorb part of this repo to merge it into your own coolq applications.
18 | ### XXXXXXXXXXXX
19 | * First follow https://cqp.cc/ and instructions to get CoolQ ready then
20 | * Start the CoolQ application and makes sure it is working properly.
21 | *** If you use docker, go here: https://github.com/CoolQ/docker-wine-coolq to deploy a docker application by
22 | ```
23 | mkdir coolq && cd coolq
24 | docker run --rm -p 9000:9000 -v `pwd`:/home/user/coolq coolq/wine-coolq
25 | ```
26 | * Follow https://cqhttp.cc/ to get http api plugin enabled on CoolQ.
27 | * then refer to https://nonebot.cqp.moe/ to get familiar with Nonebot
28 | * have required dependency:
29 | ```
30 | pip3 install nonebot
31 | ...
32 | ```
33 | * Plugin documentation is available, see it and finish initialization.
34 |
35 | ### Update since August 1 2020
36 | Since Coolq is dead, please refer to [this issue](https://github.com/nonebot/nonebot/issues/217) for alternative ways of deploying it.
37 |
38 | ### Update since March 20 2020
39 | [NoneBot](https://github.com/richardchien/nonebot) has updated to v3.5.0, abandoning the use of `Context_T` and discarding Python 3.6. As a result, this bot, after bumping versions, only runs above Python 3.7.
40 |
41 | ### Related
42 | * [scripter for sendo erika](https://github.com/cleoold/scripter-for-sendo-erika)
43 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cleoold/sendo-erika/61dcc6d7e01a59e3f454a90e3b3094eb571ff312/__init__.py
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/bot.py:
--------------------------------------------------------------------------------
1 | from os import path
2 |
3 | import nonebot
4 | import config_bot as config
5 |
6 | if __name__ == '__main__':
7 | nonebot.init(config)
8 | nonebot.load_plugins(
9 | path.join(path.dirname(__file__), 'plugins'),
10 | 'plugins'
11 | )
12 | nonebot.run(host=config.HOST, port=config.PORT)
13 |
--------------------------------------------------------------------------------
/bot.py.save:
--------------------------------------------------------------------------------
1 | import nonebot
2 |
3 | if __name__ == '__main__':
4 | nonebot.init()
5 | nonebot.load_builtin_plugins()
6 | nonebot.run(host='', port=8080)
7 |
--------------------------------------------------------------------------------
/config_bot.py:
--------------------------------------------------------------------------------
1 | from nonebot.default_config import *
2 |
3 | from utils_bot.datetime import timedelta
4 |
5 | ## ::::::::::::::::..::::::::::::::::::::::::::::::::::::::::::::.............:::::::::::::::
6 | ## :::::::,,,,,::::::..:::,::::::::::::::::,,,:::::,,,,,,:,,:::..::::::::::::...:::::::::::,:
7 | ## ::,,,,,:::::::::::::..:::,:,:::::,,,:,::,,::,,,,::::::,::::.::::::::::::::::...:::::,,,,,:
8 | ## ::,,:::::::::::::,:::::::,::::::::::::::::::,,,,;;;,,,::::.::::,:::::::::,::::.:::::::::,:
9 | ## ::::,,,:::::,::::,,:::.::::::::::,,,:,::,,;i,::::,,::,;;:::::,::::::::::::::::::.:::::::,:
10 | ## :::::::::::::,,,:,;;ii;;,.::,::::,::,:;;::::::t,:,,,,:,:,;;,::::::::::::::::::::..::,,,:,:
11 | ## ::::::::::::,:,;:,:::,::::;:::::,,,;i,:::::::i:;,,,::,,,::,:;t::::::::::::::::::::.:::::,:
12 | ## :::::::,:,:,.;,::,:,::,,,::;:::,:ii;,:::,::,;:,:;,,,,::::::,,it;::::,::::::::::::::.:,::,:
13 | ## ::::::::,:,,i,:,,::,,,;,,,,:;,,,,:.:::::::,:;::,;i,,,,:::::;;;;,;,:,:::::::::::::::.::::,:
14 | ## :::::::,:,:;::,,:;iiii,,,,;;,i:.,;;,:::::,:;:::,,:;,,,:::::,:,,,:,;:,:::::::::::::::.:::,:
15 | ## ::::::::,:;,,:,;i;,::,,,,::,;t,,ii,:::::,,,;::,:,,:,,,:::::,:,,:,,,;:,:::::::::::,:::.::::
16 | ## :::::::::;,:,i,,,::,:,:,,;i;:.;i::::::,,,,i::,,,,,,,,,:::::::::,::,:,;::::::::::::,::.::::
17 | ## :::::::,;,:i;:,::,,,:,;iti,:.,,.:.:::;:,,;,,,,,,,,,,,,,:,:::::::,::,:,;:,:::::::::,::..:::
18 | ## ::::::::;:i,:,,,,::,;i;i:,i..:.:.:::;:,:,i:,,,,,,,,,,,,,,,,::,,:,:,:,:;,:,,,,:::::,:::.:::
19 | ## ::::::,,,i;:,,:,,:,ii,;:ii,,,:.:...;:,;,;;,:,,,,,,,,,;,,,,,,::;;,:,,,::;,::,,::::,::::.:::
20 | ## :::::,:;;,:,,,,,,;i;:;:t;,,;...:.:;:,;,;i,::,,,,,,,;,,;:,,,,,,,,i,::::,,;,,:,:::::::::.:::
21 | ## ::::,:,;,:,,,,,,,i,:;,j,.;,.....:.,:;;:i;,::,:,,,,,;,,;,,;,:,,:,:,;:,,::;,,:::::::::::.:::
22 | ## :::::;,,:,,:,::;i::;;i:::; . .:.;,;,.,i;:::,:,,,,,,;,;;:i,,,;,,:,:i;,:,:;:,::::::::,::.::
23 | ## :,:,,,,::::,::,i:,;;t;:.;:....: ,:;,,:i;;::,:::,,,;,;;i,:t,,,;::,:,,t:::,;::,::::::::::.::
24 | ## :::,,,,:,::,,,t,,,it;,:;: :..: .;.;;.,t,,::,:::,,,i,i,i,,t,,,,::;,,,;,::,,,:,:::::::::::::
25 | ## ::,,::,::::::i,,,;i;;;,;.:. :..,:,,,.;i;::.,:::;,,j,t;i,,t;:,,,,,;:,;;::,,;:::::::::::.:::
26 | ## ::,:::,:::::,i:,,i;;,:i::,..:.,;.;::.ti;::.;::,,,;j,ti;,,j;,;,,,,i:,it,::,i,::::::::::.:::
27 | ## :;,,:,,,:,::i:,:;;,;,,,:;.:,.,;.i;; .ftt.:.;:,;:;t;t;tt,:j;,,,;,:;,i;i,:::i::,,,:,::::.:::
28 | ## :i::::,,:,,,;:,:t:;;:t:;,:,i,;i:tji.,ttt:..i:i,,ij:L,jj,,j;;,,i,,,;tji;::,t::,:,:::,::.:::
29 | ## ,,:::::,:,:;:,:;t,i,;j:;::;,i,,tijt,tijj:..i:i:it;ijtft,;i;;,,i,,,ittji::it::,::,tG;:.::::
30 | ## ;,,,:,::,,:;:,,t;;i:ij,;:;,,;i:jttj:titj: i:,;ij:f;tfj,t,;i,;i:,:itttt;;ii:::;fDEL,:.::::
31 | ## ,::::::::::,:,:t,i;;jt;;,;i;ijifjtt,ttif,..t;,;f,tj:fft,j:;i,;i:,,ijttjiitt:;LGDELj:.:::::
32 | ## :,:::::::::,:,;i,i;iL;i,;;ttijjtttLLitif,..j;;t;ijtjtft:j:;i,,;:,,ifttjfiittDGDEGL;:.:::::
33 | ## :::::::::::,,:t,:titf;t,iitjfijf,ititG;f;.:j;titti,t;ti;i:;,,i,,,:tLttfLfiDEDEDLGt::::,,::
34 | ## ::::::::::::,:i:,t;tG,t;t;tLjt;f,ttt;Liji.:jifij;tttii.jj,i:,j,;,:tGjjjfGLEEEDLLL,::::,:::
35 | ## :,::::::::,:,:i:,tjtL;iii;Lftj;j:i,jif;fi.;titf,;ijit,j,f,t,;G:t;,tDjjjLEEDGGfjD;.,:::::::
36 | ## ::::::::::::,,i::tttL;;tiiGjiL:tjL:jit;Lt.iiGf,:jf;;;iL;f,t;iL:Lt,tEfjfLDGDGfjjj::::::::::
37 | ## :,,,::::,::::;,,:t;jfi;tijLLiLfWWWWLi,;fj:iiG;,tjititftiL;ttjj:fj,jKLjjLDGGjjfL:,:::::::::
38 | ## :,::::::,::,,i:,,f;jfi;ttGfLtDWEt#WWf:iii:ifL,,LjtijDLGGfitifjijt;jKDfjLEfLfffD,:,,:::::,:
39 | ## :,::::::,::,:;:,,f,fititLtjGfWK.GWW#Wi,:;tijtit,;;j;G;;tfLLLfiGftfjELffLEfDLGEL,,,:,::::,:
40 | ## :,::::::,::,:;::,j,j;tttG;fDLKf t,WWWt:.,itt;t:;,;,,j;ifjfjfL;LfiLEDEGfLDEKELGD,,:::::::,:
41 | ## :,:::::::::,,;::;j,j,jttf,DGGft..:KWW;.::.f,i,,:,;::tttfLtfiffLf;GKDfLGEEKGEEEt;:,,:::::,:
42 | ## :::::::::::::,::,i:i;fijL;EjL:i DKKKK::...i::;,,;jLGGGjiLL;LtfDjtEEfjffGKEffDDt,,:::::::,:
43 | ## :,:::::::::::,:,,;,,;itLGtDjL:, GGEDE.:....:.::GW######KLijtftLiLEGjfjfGWGffGDj,,:::::::,:
44 | ## :,::::::::::,,:,,,,;,:jDDtDLL:: fLEDL........::Dt,#######fLtiGjiEELjjfGEKGjfGDf,,:::::::,:
45 | ## :,,:,::::::::,,::,,:,,GDDjLLf,:.;LWDt.........:,,,##W####Wi;GiiGEELffGDEEDffLDf:,:::::::,:
46 | ## ,,,::::::::::,,,,,,:,;DDEDftj,,:,DfG:............::DWWW###DjtjiEKDLjGEKGEEGfLDL:,:::::::,:
47 | ## ;,:.:,::::::::,:::,,:fDDEEL;t,:,:jEG ............, fWWKW#W#t;fGDEDfGKEKLDEEfLDG,::::::::,:
48 | ## ,,,:.::::::::::,,,:,;LEDEDi;;;,::::............. jKKKKEK#K#fjtGDDDDEKGEDDLEDLDf,::::::::,:
49 | ## :;;,.:,:,:,::::::,,:jfDDEf:t,:::::...............jDWKDGKWE#GLG;DEEDKfEfGDGGEDDj,,:::,:::,:
50 | ## ,:,i,.:,:,:::::::,,;;,;;f,tjt::...... :.:....... ;DK#WEGLG;ttjfGGjELLDGfDDfLGji,:,::::::,:
51 | ## ,::,;:.,,:,::::::,,:,,,L,;jtj.........i,:.......::KfEDfK;,;tjfDfjGEjGGGfDDfffG;,,,::::::,:
52 | ## :,,:;,..;:,::::,:::,;,f;itt;L;........,,:.......:;EDfLGG;;tGjLffjKDjGjGLDDLjjjL:,,::::::,:
53 | ## ,;,,,;:.:,,,:,::,::,:j;itj;iff:......:........:::::jDEGi;,GLDGffDDjLLjfLDDGLGGft:,::::::,:
54 | ## .:i,;,,:.:;:,:::::,;;i:jtiittLi.:.............::::,;;;;;iLGLGjfLDLfL;tLLGLjtjGjj:,,:::::,:
55 | ## .:.i,,i,:.,:;,,::,;,,,ititif;ft;.....iE,:.......::,;;iitjfiGfffDGL;fiiLjtt;;ttLij;::::::,:
56 | ## ;,::.i,i,::,,,:,,,:;::titiL;,jjj;..:.:LfffD,...::::,,tf;ttLDffGLtGttGi;jfiiii;ttj;,i;,,:,:
57 | ## i;,::.ii,::.,,,,,:,:,:;tjLji;iGtt,:...jtjfL,....:::,jiififL,tGD;iLLijLi;ititt;,,itti,,,,,:
58 | ## :;;,:::tj,::.,i,:,,.,:ttjt;Gf;Lj,j...:;ttjj.....:::j,ij;jt,ifWDf,;KjijLi,;i;;tj;,::ijti;;,
59 | ## ,,;;,::.,;,..:t,,;:.:,ttittDG;jG;ti...:jjj:.....:;j:ttijt;;jK#GD;;;WEf,;jGLft;,j,;;;ittjti
60 | ## i,:;;,::......t:;;:.:it;iiDEDfifL;f;:........:::j;:f;jjt,;jK##EDE,,ttjGEEKWKf;,,,, :,i;:tt
61 | ## ..,;;t::.:.:..:t,;:.:t,;;iDEDGDGDEGDL:....::.:;i:ittfii;jL##W#EjEEDKGGDGDDDDEKE:,,jL;::,;,
62 | ## ::..:;;,:..:.:.t,i,:,j,;;fDEDGGGGGGGGL:.:....,jtLi.ji;ijfG###WEEtGKDEGGDDDDDEDEG.;,tffi,,;
63 | ## ;,::.:.:.:....:;i;,:,t;;tEDEDGDDGDDGGGG;;;tj;jfj;.it,tjjt####KEDKEEGLGLGGGGDGEEK;,;tfjGti,
64 | ## ,i;:::.........:ii;:;i;;tEDEDGDDGGGGGGKEEWt,:ti;.:t;jjttD####KEEKEGLLLLLLGGGGDEEi:;i,jjfji
65 | ## ;;i;:...........iit,,;,;LDGDDGDEGDGGGDWDDK,,ii;:.j,ftit;#WW#WKEKEGLLLLLLLGGGGDEKf,i,jt;LLj
66 | ## ...............::KL;:;,iDLGDDGDDDDGGGKEEDD.,fi,.,;fi;t;jW#W#KKKEGLLLLLLLLGGGGDEEfii:L;tfff
67 | ## ,,,,::.........::;GEt:iGDGDLDLEDEDGGEEDDK:itD,:.if;;i;fW####KWDLLLLLLLLLLLLGDDEELti,fLjffj
68 | ## ,;ii,:.........:::LEGtDGGGDGDGEEEDGGEDDDD,LjD.:;ji;;;tW###WWWDLLLLLLGGGLLLGGDEEEf:;,ff;fjj
69 | ## ;,,i;,.........:::LDLGfGGGGGDGEEEDGDDDDDLffGD,:jt;;;iG##WEKKGLLLLGDDDGGLLLGDEEEKt;:,fjjjLj
70 | ## ;,,,i,::........,ifELfjLGGLGEDKEDGGGGGGGLfLGG,:L,;;ifWWEDEEGLLLGDEDGLLLLLGDDEEEDii;,ffLfLt
71 | ## :,;,;,,::::..:..:fLDfLfLLGGGDDWDDLGGGLGGfjDGf;:i::,tLEDEEDfLLGEEEDGLLLLLGGDEEEEtL,i:fLGjfi
72 | ## ,,,;,;,,:::..:::,LLD:fL;GLLDDEEGLGGLLLLjfjDfG;,,.:ifEDDEGLGEEEEGLLLLLLLLGEEEEKGfji;:ffjLtj
73 | ## :::,,,;,,::::,::GDGKG:LiLDGGDKGLLLLLLffj.GELGji;:;:DDDDGGKKEDDLLLLLLLLLGDEEEEGEf,t:ifftjLE
74 | ## :,,:,;;;,,,,i.;GDL;GKfj;GLDDEELLLfLfLLti:DDfDti;,:iDDDDGWEEGLGLLLLLLLLGDEEEEDEDji;:ffLjjEE
75 | ## ::,,:,,iGiii,jDDDG;:GK:;fLGDEDLLEfLLfjf;fDfGGLtt:,LDEEDWEDGGLLLLLLLLLGDEEDEDDEDtt,iLftfLDE
76 | ## :::,::;fDjiiEEDDELLj:LD,LfLLELLfGEfftif:GE,GGfjij;GDDEWWGGGLLLLLLLLLGEEEDEDGKEGi;;fLf;LLDE
77 | ## :::::,:EE;tWWWKEGGGfi:Df,LLLGGfffLDfij,tDf:GDjtj,G;fEEWEGGGLLLLLLLLGEEEDDELEEKLt,jGLf,GjED
78 | ## :::::,i#WWW#WWDGGG;jLL;iG:ffGLDGLLLLLG.GL,jGG;jiGKGj;EKDGGLLLLLLLLGEEGGEDtEKEWL;tDELL,LGLE
79 | ## ::::,:LW#W#WKDDGG;tGf,Gf,L;LLLGDGGGGGG,Gi,LGG;j;EDLDiGDGGLLLLLLLLDEDGGDDEGEEEWL;fDKDf;jDLG
80 | ## ::::,,LWW##EEEDDijGj;LGfG;j;fLLGDDGDGLGG:;GGGii;DLLLGjEGGLLLLLLLDEDGGDDEGKEEKKLiGEEKf;ijDG
81 | ## :::::,.GWWEEDEDtfGj;LLfGLGitLLLLGDDDtLDj:tLGGL;tGLLGEjDGLLLLLLGDEGGGDDEEjEEEKEGtDKEEfi,tiG
82 | ## ::::.::DKEEEELiGEtfGGLLLLLLf;LLLGLEE:GL,.;LDDL,GLLLDEfGLLLLLLLEDLGGDEEEEtEEEEEDfEEDGEt,it;
83 | ## ::::::,GEEEDtfDEjLDDGGGGLLLLjtLLLGDEtLG:,.fGLifLLGEEDLGGLLfLGELLGGDDEEEEtEEEEEELEDDDEG;,it
84 | ## :::::,,,;GtGEDjfEEEDDGGGLLLLfLLLLLGLDG:.:.tLfGGGGGGGGGGLLGDDGLGLGDEEEEEEfKEKKEEfEEEDGGD;i,
85 | ## :,,:,:;::iGELtGEEEEEEDGGLLGLLLLGGGLGLG:,..ttjDDDDGEGGGGGDEDLLLGGDDEEEEKEGKKKEEEfEEDGGLGL;;
86 | ## :::::::,,,itfDEEEEEEEDDGGGLLLLLLGGLLGLDi,:tjGDDDDEDGGDEEDLLLGLGGDEEEEEKKEKKEEEEDGDGGGGGDj;
87 | ## :::::,:,;,,tEDEEEEEEEEDDGGLLLLLLGGLLLGLL:,jGEEEEEEGEKEEDLLLLGGDDEEEEEEWWWEEEEDEDGGGGGGGGE,
88 | ## :::::::::,;;EDDEEEEEEEEDDGGLLLLLGGGLLLGGL;GDKKKKKDKEEEGfLLGLGGDEEEEEEKWWEGKEEDGGGGGGGGDGGi
89 | ## ::::::::,:,DDEKEEEEEEEEEEDGGGLLLGDDGLLLGGKDEWKWEKEKDLLLLLLLGGDEEEEEKWKKKEKDEDGGGGGDDDDGLLf
90 | ## :::::::::,:EEEEEEEEEEEEEEDDGGLLLGDDGLLLLLDEEEKKWKEDLLLLLLLLGDEEEEEEWKKKKEKEDGGGGGDDDDGLGDt
91 | ## ::::::::,:fGEEKEEEEEEEEEEEEDGGLLGDDDGLLLGGEEEDEGGGLLLLLLGGGGDEEEEEKKEEEKKEEGGGGGDDEDGGGEEt
92 | ## :::::::::,DEEDDEEDEEEEEEEEEEDGLLLGEDDLLLLGEEDKDKEEEEDDDGGLGDEEEEEKWEEEEKKEEGGGDEEEDGDDEEEL
93 | ## ::,::,:::jDDEDEDDDDEEEEEEEEEDGGLLGEEDGLLLLDEEEDKKGGEEEEEEGGDEEEEKWEEEKKKKEDGDEEDGGDEEKEGDG
94 | ## :::::::::DDDGEGGDGGDEEEEEEEEDDGLLLDEDGLLLLGDEDDDKEKLLGDDEGGDEEEEKKEEEKKKKEDEEEDDDEEEEGLLGD
95 |
96 | SUPERUSERS = { }
97 | SELF_QQ = 0
98 | COMMAND_START = {''}
99 | NICKNAME = {'千堂', '千堂 瑛理華', '千堂瑛理華', '千堂瑛理华',
100 | '千堂 瑛理华', '千堂瑛里华', '千堂 瑛里华', '瑛里华', '瑛理华', 'erika'}
101 | SESSION_EXPIRE_TIMEOUT = timedelta(minutes=2)
102 |
103 | HOST = '172.17.0.1'
104 | PORT = 8080
105 |
106 | DEBUG = False
107 |
108 | # PLUGIN-SPECIFIC SETTINGS
109 |
110 | AMAP_WEATHER_API_KEY = ''
111 |
112 | OPENWEATHERMAP_API_KEY = ''
113 |
114 | GLOT_RUN_TOKEN = ''
115 |
--------------------------------------------------------------------------------
/doc_assets/custom_reply.md:
--------------------------------------------------------------------------------
1 | In a group chat, you might want the bot to do a "keyword reply". For example, if someone says `在吗?` the bot replies `在!`.
2 | The custom reply plugin is based on the private chat window. By chatting with the bot with commands one can easily modify the keyword settings.
3 |
4 | All matchings are stored in a json file called `group_data.json` under its module path. Matchings split into qq groups, which means these settings are group-specific. One special part is there exists a "group number" called `global`, which means keywords in this dict respond to every group.
5 |
6 | ```
7 | ┌ "global": .... groups 123456 654321 also apply
8 | settings-┼ "123456": ....
9 | └ "654321": ....
10 | ```
11 |
12 | In each group, there are three modes: full match (1), inclusive match (2), and regex match (3).
13 | * full: replies only when the keyword completely matches the message
14 | * inclusive: replies when keywords are *in* the message
15 | * regex: replies when the message matches given pattern
16 |
17 | ##### Creating keyword pairs
18 | Open a private message box with the box as a superuser. hit and observe
19 | ```
20 | >> 群关键字 add global 3
21 | 在这里输入关键字
22 | >> ^[A-Z]{3,4}[-\._]?[0-9]{3,5}$
23 | 在这里输入回复
24 | >> ナニコレ??
25 | success!
26 | ```
27 | In the first line, `群关键字` is the name of the command, `add` is the add mode which means you are adding keywords, `global` means you are adding stuff in the global folder so that it works in every group, `3` means the keyword works in regex-matching mode.
28 | You then typed `^[A-Z]{3,4}[-\._]?[0-9]{3,5}$`, this is a keyword. You then typed the reply, and the bot responds with a success message. The pair will take effect instantly.
29 |
30 | Thus when any group member's message matches this pattern, like `AAA1111`, the bot replies with `ナニコレ??`.
31 |
32 | Or it might say `?`, this is because this keyword already exists in the factory configure file, adding an existing keyword is in fact appending: two replies both exist and a randomly chosen one will be sent. This is why in the configure the reply is in the form of a list.
33 |
34 | ##### Removing keyword pairs
35 | Note the deleting mode will delete *all* replies paired with the given keyword.
36 | ```
37 | >> 群关键字 del global 3
38 | 在这里输入关键字
39 | >> ^[A-Z]{3,4}[-\\._]?[0-9]{3,5}$
40 | success!
41 | ```
42 | The match we just set was then deleted. In other occasions, if you typed a keyword that does not exist, an error will be reported.
43 |
44 | Note, instead, you can actually delete all pairs in one group at once:
45 | ```
46 | >> 群关键字 delall 123456
47 | success!
48 | ```
49 |
50 | ##### Editing keyword pairs directly from the json file
51 | The json file come along has its pre-setup reply pairs which will guide you the proper format to edit them.
52 |
53 | ##### Variable as reply
54 | In any reply, you can insert variables. To plug a variable inside the content, just type these in place of the variable:
55 | * `{SENDER_ID]` sender's qq
56 | * `{SENDER_NICK]` sender's nickname
57 | * `{SENDER_CARD]` sender's namecard
58 | * `{SENDER_ROLE]` sender's role (member or admin)
59 | * `{SENDER_TITLE]` sender's title
60 |
61 | The availability of them depends on the context.
62 |
63 | ##### Checking keyword pairs
64 | This command will list the first 10 replies of *each* keyword match
65 | ```
66 | >> 群关键字 view global 3
67 | global, regex_match
68 | "^[A-Z]{3,4}[-\._]?[0-9]{3,5}$": "?"; "ナニコレ??"
69 | ```
--------------------------------------------------------------------------------
/doc_assets/evaler.md:
--------------------------------------------------------------------------------
1 | This feature is provided by https://glot.io (whose github webpage is https://github.com/prasmussen/glot-run/) and its associated api. Example:
2 | ```c#
3 | >> exe c#
4 | class MainClass {
5 | static void Main() {
6 | System.Console.WriteLine("Hello World!");
7 | }
8 | }
9 | --------------------------------------
10 | stdout: Hello World!
11 | stderr:
12 | error:
13 | ```
14 |
15 | You must visit the page above to create a free account and then go to https://glot.io/account/token to obtain an api key. fill in the key in the `GLOT_RUN_TOKEN` variable in the file `config_bot.py`.
--------------------------------------------------------------------------------
/doc_assets/notifyme.md:
--------------------------------------------------------------------------------
1 | You can talk to the bot to schedule a timer, when the timer expires, the bot will get back to you
2 |
3 | ```
4 | [11:00:00] > 千堂定时提醒 5 30 吃饭
5 | [11:00:00] 已设定:
6 | 05月06日 16:30 吃饭
7 | ...
8 | [16:30:00] @你 吃饭
9 | ```
10 |
11 | Partial natural language is supported. example:
12 |
13 | ```
14 | [11:00:00] > 千堂5小时30分后提醒我吃饭
15 | [11:00:00] 已设定:
16 | 05月06日 16:30 吃饭
17 | [11:00:20] > 千堂取消定时提醒
18 | [11:00:20] 已取消定时提醒
19 | ```
20 |
21 | limitation:
22 |
23 | currently the scheduled job store is not persistent, which means after rebooting the bot all scheduled jobs will be lost.
24 |
--------------------------------------------------------------------------------
/doc_assets/remotely.md:
--------------------------------------------------------------------------------
1 | This plugin is simple. By chatting with the bot as a superuser with
2 | ```
3 | 发送到QQ 12345678 hello, world
4 | ```
5 | You sent a message to the user. You can also send messages to groups by using
6 | ```
7 | 发送到群 12345678 hello, world
8 | ```
9 | Using following you can embed CQ codes:
10 | ```
11 | 发送到QQCQ 876543210 [CQ:face,id=14]
12 | 发送到群CQ 12345678 [CQ:at,qq=876543210]
13 | ```
--------------------------------------------------------------------------------
/doc_assets/repeater.md:
--------------------------------------------------------------------------------
1 | By default, when a same message in *one* group repeats 3 times, the bot will speak the same sentence once and only once. You can change this number by inspecting `__init__.py` under `/repeater`, the third line from the bottom.
--------------------------------------------------------------------------------
/doc_assets/signin.md:
--------------------------------------------------------------------------------
1 | involke in a group chat like this:
2 | ```
3 | > 千堂签到
4 | @你 早安! 好感度:1.8 (+0.4)
5 | > 千堂签到
6 | 今日签到过啦~ 好感度:1.8
7 | > 千堂签到信息
8 | 好感度:1.8
9 | 历史签到次数:5
10 | 上次签到:2019.08.27
11 | > 千堂签到排名
12 | ...
13 | ```
14 |
15 | This plugin overlaps with test_rp plugin. Please remove it to use this.
16 |
17 | The sign_in plugin provides basic daily signing feature. It is a group-based feature. User in different groups can sign in and gain points.
18 |
19 | The data is stored in a sqlite database and is managed by `SignInSession` class. The structure of the signin data is dipicted as follows
20 |
21 | ```
22 | table name: sign
23 |
24 | fields:
25 | identity (format: userid_groupid)(str),
26 | last sign in time (str),
27 | score (int),
28 | luck (not used)(str),
29 | score2 (stores the sign in count)(int),
30 | score3 (not used)(int)
31 | ```
32 |
33 | There are some fields that are not used. Feel free to implement.
34 |
35 | A row fetch looks like this:
36 | ```py
37 | ('12345678_7777777', '27082019', 180, '', 5, 0)
38 | ```
39 |
40 |
--------------------------------------------------------------------------------
/doc_assets/start.md:
--------------------------------------------------------------------------------
1 | ### START
2 |
3 | open config_bot.py and modify:
4 | * `SUPERUSERS: dict[int]` This contains all qq IDs that have full control to the bot, type yours here.
5 | * `SELF_QQ: int` Bot's qq.
6 | * `COMMAND_START: dict[str]` the prefix to call the bot. If you have an empty string `''` this means no prefix will be used.
7 | * `NICKNAME: dict[str]` Applies only in a group chat, except special settings, the bot will respond only to those messages which start with an `@` or this nickname, for example:
8 | ```python
9 | 千堂查天气 new york # responds
10 | 查天气 new york # does not respond
11 | ```
12 | * Change `HOST` and `PORT` as appropriate; because CoolQ http plugin will open a server to process requests, you plug in its location. Refer to https://cqhttp.cc/docs/4.10/#/ if you do not know.
13 |
14 | * run `python3 bot.py` and the bot is working. If there are exceptions prompting you to install modules, do so.
15 |
16 | Open a private message window with the bot, and hit:
17 | ```
18 | 发送到QQ 12345678 hello, world
19 | ```
20 | Where you know where your qq goes (12345678). Since it does not matter in private chats whether you call the nickname, you will see:
21 | ```
22 | hello, world
23 | success!
24 | ```
25 | The first message indicates you controlled the bot to send a message to you: "hello, world", the other says it is successful. Sometimes if you do not see the success! message, there might be some problems.
26 |
27 | Now the bot is working properly. But to use more features, read the following docs...
28 |
29 | Or you might want to type `help` to the bot.
--------------------------------------------------------------------------------
/doc_assets/weather.md:
--------------------------------------------------------------------------------
1 | This plugin currently supports two data sources: 高德 (Amap) and OpenWeatherMap. Amap will fetch the weather data for cities in China, and OWM works for anywhere outside (in English)
2 |
3 | A sample Chinese city search looks like:
4 | ```
5 | >> 千堂 天气 香港
6 | --------------------------------------
7 | 预报时间:2019-05-29 22:51:39
8 | 地区:香港 香港特别行政区
9 | 2019-05-29 日:27°C,阴,无风向
10 | 2019-05-29 夜:24°C,阵雨,无风向
11 | ......
12 | ```
13 | Where `千堂` is my nickname. This 3-day forecast result is given by Amap. While if an English name is passed, then the result looks like:
14 | ```
15 | >> 千堂 天气 montreal
16 | --------------------------------------
17 | region: MONTREAL, CA, time diff from UTC: -4.0h
18 | report time: 2019-05-29 18:00:00
19 | 2019-05-29 18:00: Clouds (overcast clouds), 16.44-17.91°C
20 | wind: 3.96m/s (222.787°), humidity: 65, pressure: 1004.83hPa
21 | 2019-05-30 06:00: Clouds (broken clouds), 10.46°C
22 | wind: 2.46m/s (266.48°), humidity: 95, pressure: 1005.19hPa
23 | ......
24 | ```
25 | This is given by OWM. But if you pass a Chinese string which does not correspond to a Chinese city, the translator module is activated (1000 times per day, as documented):
26 | ```
27 | >> 千堂 天气 蒙特利尔
28 | --------------------------------------
29 | region: MONTREAL, CA, time diff from UTC: -4.0h
30 | ......
31 | ```
32 |
33 |
34 | To use this, you must request their free api keys separately.
35 |
36 | For 高德 (Amap), go to https://lbs.amap.com/api/webservice/guide/api/weatherinfo/ and paste the key in the `AMAP_WEATHER_API_KEY` variable in `config_bot.py`.
37 |
38 | For OWM, go to https://openweathermap.org/forecast5 and paste the key in the `OPENWEATHERMAP_API_KEY` variable in `config_bot.py`.
--------------------------------------------------------------------------------
/plugins/_googlesearch/__init__.py:
--------------------------------------------------------------------------------
1 | from nonebot import CommandSession, on_command
2 | from nonebot.permission import *
3 |
4 | from utils_bot.command_ops import global_cooldown
5 | from utils_bot.logging import logger
6 | from utils_bot.typing import depreciated
7 |
8 | from .data_source import getGoogling
9 |
10 | __plugin_name__ = 'google'
11 | __plugin_usage__ = r'''feature: google search
12 |
13 | google 获取前3条 google search 结果
14 |
15 | DEPRECIATED
16 | '''
17 |
18 |
19 | @on_command('google', permission=SUPERUSER | GROUP_MEMBER)
20 | @global_cooldown(40)
21 | @depreciated
22 | async def google(session: CommandSession):
23 | try:
24 | keyword = session.get('keyword')
25 | report = await getGoogling(keyword)
26 | await session.send(report)
27 | logger.info(f'google search called: {report[:37]}...')
28 | except ValueError:
29 | await session.send('error')
30 |
31 | @google.args_parser
32 | @depreciated
33 | async def _(session: CommandSession):
34 | paramStr = session.current_arg_text
35 | # if arg list is not empty
36 | if paramStr:
37 | session.state['keyword'] = paramStr.strip()
38 | else:
39 | session.finish(__plugin_usage__)
40 |
--------------------------------------------------------------------------------
/plugins/_googlesearch/data_source.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from aiohttp import request
4 | import bs4
5 |
6 | from utils_bot.typing import depreciated
7 |
8 | # 052219: adding browser headers creates cache in resulting page
9 | _headers = {
10 | 'Cache-Control': 'private, max-age=0, no-cache',
11 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
12 | 'Accept-Language': 'en-US,en;q=0.5',
13 | 'Accept-Encoding': 'gzip, deflate',
14 | 'DNT': '1',
15 | 'Connection': 'keep-alive',
16 | 'Upgrade-Insecure-Requests': '1' }
17 | _browser = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0' }
18 |
19 | @depreciated
20 | async def getGoogling(*keyword) -> str:
21 | header = _headers
22 | res = '>_< '
23 | try:
24 | count = 0
25 | linkElems, greenElems = [], []
26 | while len(linkElems) == 0:
27 | async with request(
28 | 'GET', 'https://google.com/search?q=' + keyword[0],
29 | headers=header) as resPage:
30 | soup = bs4.BeautifulSoup(await resPage.text(), features='lxml')
31 |
32 | # linkElems contains titles and GOOGLE URLS (without domain prefix)
33 | linkElems = soup.select('.r a')
34 | # greenElems contains displaying urls
35 | greenElems = soup.select('cite')
36 | count += 1
37 | if count == 10:
38 | header = dict(_headers, **_browser)
39 | elif count == 12:
40 | raise Exception('Google 好像此时不想让我们连接')
41 |
42 | displayLen = 3
43 |
44 | linkElems = linkElems[:3]
45 | greenElems = greenElems[:3]
46 |
47 | except Exception as exc:
48 | return str(exc)
49 |
50 | def parseOneGoogleUrl(gUrl) -> str:
51 | return re.search(r'q=(.+?\..+?)&[a-z]+=[A-Z]', gUrl).group(1)
52 |
53 | for j in range(displayLen):
54 | try:
55 | realUrl = parseOneGoogleUrl(linkElems[j].get('href'))
56 | except Exception:
57 | realUrl = greenElems[j].getText()
58 | res += linkElems[j].getText() + '\n' + realUrl + '\n'
59 |
60 | return res
61 |
--------------------------------------------------------------------------------
/plugins/_sign_in/__init__.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | from os import path
3 |
4 | from nonebot import CommandSession, get_bot, on_command
5 | from nonebot.permission import *
6 | from aiocqhttp.exceptions import ActionFailed
7 |
8 | from utils_bot.logging import logger
9 | from utils_bot.typing import Tuple
10 |
11 | from .execute import SignInSession, format_score, generate_luck_result
12 | from .greets import get_greeting
13 |
14 | ## this plugin overlaps with test_rp plugin
15 | ## 和 test_rp (今日运气)功能重合,欲启用此请先停用 test_rp
16 |
17 | __plugin_name__ = '签到/运气'
18 | __plugin_usage__ = f'''feature: 要不要看一看自己的人品?
19 | 功能:签到,签到信息,今日运气,签到排名
20 | '''
21 |
22 |
23 | bot = get_bot()
24 |
25 | SIGN_IN_DB_PATH = path.join(path.dirname(__file__), 'signin.db')
26 |
27 | # initialize db obsolete
28 | @bot.server_app.before_serving
29 | async def initialize_db():
30 | async with SignInSession(SIGN_IN_DB_PATH, 0, 0) as table_init:
31 | logger.info('loading signin db...')
32 | await table_init.init_table()
33 |
34 |
35 | def get_user_and_group_ids(session: CommandSession) -> Tuple[int, int]:
36 | user_id: int = session.event['user_id']
37 | group_id: int = session.event['group_id']
38 | return user_id, group_id
39 |
40 |
41 | @on_command('签到', aliases=('sign',), permission=GROUP_MEMBER)
42 | async def sign_in(session: CommandSession):
43 | user_id, group_id = get_user_and_group_ids(session)
44 | async with SignInSession(SIGN_IN_DB_PATH,
45 | user_id, group_id) as signin_session:
46 | await signin_session.init_user()
47 | status, score, added = await signin_session.user_sign_in()
48 | if status:
49 | await session.send(
50 | f'{get_greeting(score)} 好感度:{format_score(score)} (+{added})',
51 | at_sender=True)
52 | else:
53 | await session.send(
54 | f'今日签到过啦~ 好感度:{format_score(score)}',
55 | at_sender=True)
56 |
57 | logger.info(f'{user_id} trying to sign in in group {group_id} success: {status}')
58 |
59 |
60 | @on_command('签到信息', aliases=('信息', 'signinfo', '好感度'), permission=GROUP_MEMBER)
61 | async def check_sign_in_info(session: CommandSession):
62 | user_id, group_id = get_user_and_group_ids(session)
63 | async with SignInSession(SIGN_IN_DB_PATH,
64 | user_id, group_id) as signin_session:
65 | await signin_session.init_user()
66 | score, count, last = await signin_session.user_check()
67 | await session.send(
68 | f'\n好感度:{format_score(score)}\n历史签到次数:{count}\n上次签到:{last[4:]}.{last[:2]}.{last[2:4]}',
69 | at_sender=True)
70 |
71 |
72 | @on_command('我的运气', aliases=('运气', '今日运气', '今日人品', '我的人品', 'jrrp', '运势', '今日运势'), permission=GROUP_MEMBER | SUPERUSER)
73 | async def my_luck_today(session: CommandSession):
74 | senderId: int = session.event['user_id']
75 | await session.send(generate_luck_result(senderId), at_sender=True)
76 |
77 |
78 | @on_command('签到排名', aliases=('好感度排名'), permission=GROUP_MEMBER)
79 | async def signin_ranking(session: CommandSession):
80 | group_id: int = session.event['group_id']
81 | async with SignInSession(SIGN_IN_DB_PATH, 0, group_id) as signin_session:
82 | ranking = await signin_session.group_top_five()
83 |
84 | async def line(row):
85 | user_id, score = row
86 | try:
87 | name = (await bot.get_group_member_info(group_id=group_id, user_id=user_id))['card'] \
88 | or (await bot.get_stranger_info(user_id=user_id))['nickname']
89 | except ActionFailed:
90 | # user left group
91 | name = user_id
92 | return f'{format_score(score).ljust(8)}: {name}'
93 |
94 | result = await asyncio.gather(*(line(row) for row in ranking))
95 | await session.send('好感度排名:\n' + '\n'.join(result))
96 |
--------------------------------------------------------------------------------
/plugins/_sign_in/execute.py:
--------------------------------------------------------------------------------
1 | import random
2 | from typing import List
3 |
4 | import aiosqlite
5 |
6 | from utils_bot.datetime import TZ, datetime
7 | from utils_bot.typing import Tuple, Union
8 |
9 |
10 | def today_to_str() -> str:
11 | return str(
12 | datetime.now(TZ).strftime('%m%d%Y')
13 | )
14 |
15 |
16 | def generate_luck_num(sender_id: int) -> float:
17 | 'a user has a luck number between 0 and 1 every day'
18 | senderId: int = sender_id
19 | timeStamp: int = int(today_to_str())
20 | seed: int = (senderId * 2) | (timeStamp * 333)
21 | random.seed(seed)
22 | res: float = random.random()
23 | random.seed()
24 | return res
25 |
26 |
27 | def generate_luck_result(sender_id: int) -> str:
28 | 'converts the luck number of a user to a suitable string'
29 | def return_luck_by_num(num: float) -> str:
30 | if 0.0 <= num < 0.1:
31 | return '极坏'
32 | elif 0.1 <= num < 0.4:
33 | return '坏'
34 | elif 0.4 <= num < 0.7:
35 | return '一般'
36 | elif 0.7 <= num < 0.9:
37 | return '好'
38 | else:
39 | return '极好'
40 | return return_luck_by_num(generate_luck_num(sender_id))
41 |
42 |
43 | def user_score_to_user(i: int) -> float:
44 | "a user's score is stored in int, but the displayed value is that divided by 100 (by now)"
45 | return i / 100
46 |
47 |
48 | def format_score(s: float) -> str:
49 | 'format the displayed score (好感度) by hearts'
50 | if s < 100:
51 | return str(s)
52 | else:
53 | # example: '4.44 ♥' means 104.44
54 | return f'{float(s % 100):.4} {"♥" * int(s // 100)}'
55 |
56 |
57 | class SignInSession:
58 |
59 | '''
60 | Table attributes:
61 |
62 | table name: sign
63 |
64 | identity (format: userid_groupid)(str),
65 | last sign in time (str),
66 | score (int),
67 | luck (not used)(str),
68 | score2 (stores the sign in count)(int),
69 | score3 (not used)(int)
70 | '''
71 |
72 | def __init__(self, db_name: str,
73 | user_id: Union[str, int],
74 | group_id: Union[str, int]):
75 |
76 | self.conn = aiosqlite.connect(db_name)
77 | self.user_id: int = int(user_id)
78 | self.group_id = int(group_id)
79 |
80 | @property
81 | def identity(self) -> str:
82 | return f'{self.user_id}_{self.group_id}'
83 |
84 | async def searchall(self) -> list:
85 | cur = await self.conn.execute('select * from sign')
86 | res: list = await cur.fetchall() # type: ignore
87 | await cur.close()
88 | return res
89 |
90 | async def init_table(self):
91 | cur = await self.conn.execute(
92 | '''CREATE TABLE IF NOT EXISTS sign
93 | (identity VARCHAR(30) PRIMARY KEY,
94 | lastsign VARCHAR(10),
95 | score INT,
96 | luck VARCHAR(10),
97 | score2 INT,
98 | score3 INT)'''
99 | )
100 | await cur.close()
101 | await self.conn.commit()
102 |
103 | async def init_user(self):
104 | 'create one entry for a user who wants to sign in'
105 | cur = await self.conn.execute('''INSERT OR IGNORE INTO sign
106 | (identity, lastsign, score, luck, score2, score3)
107 | values (?, ?, ?, ?, ?, ?)''',
108 | (self.identity, '0', 0, '', 0, 0))
109 | await cur.close()
110 | await self.conn.commit()
111 |
112 | async def user_sign_in(self) -> Tuple[bool, float, float]:
113 | '''after user initializing, signs in. one user signs in once a day.
114 | returns the successfulness of the signing in. returns the score after signing in. returns the score added
115 | '''
116 |
117 | today: str = today_to_str()
118 | async with self.conn.execute('SELECT * FROM sign WHERE identity=?', (self.identity,)) as cur:
119 | currentEntry = await cur.fetchone()
120 | scoreBefore: int = currentEntry[2]
121 | # checks sign in time, refuses if already signed in
122 | if currentEntry[1] == today:
123 | return False, user_score_to_user(scoreBefore), 0
124 |
125 | scoreAdded: int = int(generate_luck_num(self.user_id) * 100)
126 | scoreAfter: int = scoreBefore + scoreAdded
127 | await cur.execute('UPDATE sign SET score=?, lastsign=?, score2=score2+1 WHERE identity=?',
128 | (scoreAfter, today, self.identity))
129 | await self.conn.commit()
130 | return True, user_score_to_user(scoreAfter), user_score_to_user(scoreAdded)
131 |
132 | async def user_check(self) -> Tuple[float, int, str]:
133 | 'returns the score, sign-in count, last sign-in time for the user'
134 | async with self.conn.execute('SELECT * FROM sign WHERE identity=?', (self.identity,)) as cur:
135 | currentEntry = await cur.fetchone()
136 | return user_score_to_user(currentEntry[2]), currentEntry[4], currentEntry[1]
137 |
138 | async def group_top_five(self) -> List[Tuple[int, float]]:
139 | 'returns list of users\'s qq followed by score, ordered descending'
140 | res = await self.conn.execute_fetchall('''SELECT identity, score FROM sign
141 | WHERE identity LIKE ?
142 | ORDER BY score DESC
143 | LIMIT 5''',
144 | (f'_{self.group_id}',))
145 | return [(int(row[0].split('_')[0]), user_score_to_user(row[1])) for row in res]
146 |
147 | async def __aenter__(self) -> 'SignInSession':
148 | await self.conn
149 | return self
150 |
151 | async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
152 | await self.conn.close()
153 |
--------------------------------------------------------------------------------
/plugins/_sign_in/greets.py:
--------------------------------------------------------------------------------
1 | from random import choice
2 |
3 | GRP_1 = [
4 | '我是学院中最有人气的女生。',
5 | '要想获得本大小姐的青睐,可不是件容易的事噢?',
6 | '我——是——大——小——姐!',
7 | '请挺起胸膛、在这里我们才是主角!',
8 | '你知不知道、好奇心会杀死猫这句话?',
9 | '不过算了。因为我现在心情很好。',
10 | '啊……嗯?',
11 | '太邋遢了哦',
12 | '早安!'
13 | ]
14 |
15 | GRP_2 = [
16 | '呐,到底是哪里?',
17 | '如果会后悔的话,就不会来这里了。',
18 | '那也太凄凉了吧。我会花些心思的。',
19 | '因为没办法才照顾你的哟,麻烦好好地感谢我一下!',
20 | '麻烦好好地照顾我一下!',
21 | '一,一大早的说什么呢你!',
22 | '谢,谢……',
23 | '星空好美啊',
24 | '为什么在发抖?',
25 | '听说城市里都看不到星星呢',
26 | '人们会有点寂寞吧,那样子……',
27 | '欢迎回来'
28 | ]
29 |
30 | GRP_3 = [
31 | '好了,一鼓作气地上吧!',
32 | '这么令人愉快的早晨,还是第一次',
33 | '海水浴?',
34 | '没事的,我已经镇定下来了',
35 | '对了,来喝杯茶吗?',
36 | '我也是第一次有那种感觉,连自己都吓了一跳',
37 | '诶……是,是吗',
38 | '嗯,真让人期待',
39 | '马上就到讲堂了,加油啊',
40 | '啦~啦啦~~',
41 | '我哪里像反派了?',
42 | '不·要·生·气',
43 | '好,好了,再不快点真的会迟到的哦',
44 | '什么嘛,这不是走得挺快的么',
45 | '了解。稍等一下哦',
46 | '冰柠檬茶,这里做的可是非常好哦',
47 | '抱歉。我喝不来苦的东西',
48 | '话说回来,今天,你有时间么',
49 | '太好了,希望你能陪我一下',
50 | '不用在意,这也是自然的',
51 | '呀啊!? 啊?哎?',
52 | '唉,又来了么',
53 | '话说你又如何?有女朋友么?你的素质可是很高的,要加油哦'
54 | ]
55 |
56 | GRP_4 = [
57 | '在这大家庭里面,你不感到幸福吗?',
58 | '呐,以后打算怎么办啊?',
59 | '总感觉你说了很帅气的话',
60 | '你明白的吧?',
61 | '呜啊啊啊啊啊啊啊!!',
62 | '啊,是,是呢',
63 | '自作自受,偷窥可不是什么好习惯',
64 | '不要太捉弄我啊',
65 | '刚刚还夸下海口,说什么【可以尽可能把自己心中的烦恼对他人倾诉了】 我真是……虚伪呢',
66 | '拿你没办法',
67 | '被这样子抚摸着,总觉得好安心',
68 | '我没有想和谁交往的想法,之前不是说过了么',
69 | '不要戏弄我啊!',
70 | '呵呵,说不定是这样的呢'
71 | ]
72 |
73 | GRP_5 = [
74 | '你,你要让我说什么啊?',
75 | '…………我们的关系,算是那个……了吗?',
76 | '为什么我的心要跳得这么快啊,为什么离开你就会寂寞,为什么你总是令我不知所措。你这该死的笨蛋,为什么总是来招惹我啊!',
77 | '至少,我能确信自己的这份感情了',
78 | '嗯。让对方了解到自己时的开心,跟血的欲求是没有关系的吧?',
79 | '能让对方了解自己,不是很值得开心的事情吗',
80 | '我,我喜欢……',
81 | '我,我喜欢……呜啊啊啊啊啊啊啊!!',
82 | '为,为什么那么高兴啊',
83 | '嗯,我也是,请多关照',
84 | '对不起,你明明是一片好心',
85 | 'kiss~',
86 | '要好好闭上眼才行的'
87 | ]
88 |
89 | GRP_6 = [
90 | '就会开始想一些下流的事情?',
91 | '早上好老公……开玩笑的',
92 | '啊,嗯,嗯',
93 | '我也这么想的,那样的也还是第一次呢。简直就像是在吵架一样',
94 | '如果那种方式是常态反而伤脑筋了……',
95 | '又在想什么色色的事情了吧?',
96 | '我也会不好意思的啊,稍微称赞一下也好嘛',
97 | '只是想戏弄你一下而已',
98 | '嗬~',
99 | '那,一会儿见',
100 | '我还是第一次去海边玩',
101 | '说,你喜欢我',
102 | '啊……稍,稍微……等一下',
103 | '我会好好地照料你的',
104 | '那么,我给你做饭',
105 | '结果一整天都在忙个不停啊',
106 | '感觉,好幸福呢',
107 | '结婚,是么……',
108 | '真是的……笨蛋',
109 | '第一次相遇是在这里呢',
110 | '那边会不会也是樱花盛开的时节呢?',
111 | '啾……嗯……嗯啊,嗯'
112 | ]
113 |
114 | def get_greeting(score: float) -> str:
115 | if 0 <= score < 5:
116 | return choice(GRP_1)
117 | elif 5 <= score < 20:
118 | return choice(GRP_1 + GRP_2)
119 | elif 20 <= score < 50:
120 | return choice(GRP_2 + GRP_3)
121 | elif 50 <= score < 80:
122 | return choice(GRP_3 + GRP_4)
123 | elif 80 <= score < 100:
124 | return choice(GRP_4 + GRP_5)
125 | elif 100 <= score:
126 | return choice(GRP_5 + GRP_6)
127 | raise Exception('invalid affinity')
128 |
--------------------------------------------------------------------------------
/plugins/azurlane_buildship_simulator/__init__.py:
--------------------------------------------------------------------------------
1 | from nonebot import on_command, CommandSession
2 | from nonebot.permission import *
3 | from .simulator import *
4 |
5 | __plugin_name__ = '碧蓝航线建造模拟'
6 | __plugin_usage__ = r'''feature: 碧蓝航线建造模拟
7 | 可用命令:
8 | 轻型舰建造,重型舰建造,特型舰建造
9 | 参数:
10 | [次数]次 不超过10次
11 | attribution @ 碧蓝航线wiki
12 | '''
13 |
14 | @on_command('碧蓝航线建造模拟', aliases=('碧蓝航线建造'), permission=GROUP_MEMBER | SUPERUSER)
15 | async def build_help(session: CommandSession):
16 | await session.send(__plugin_usage__)
17 |
18 | @on_command('轻型舰建造', permission=GROUP_MEMBER | SUPERUSER)
19 | async def light_build_host(session: CommandSession):
20 | times = session.get('times')
21 | await session.send(mass_ship_build_light(times))
22 |
23 | @on_command('重型舰建造', permission=GROUP_MEMBER | SUPERUSER)
24 | async def heavy_build_host(session: CommandSession):
25 | times = session.get('times')
26 | await session.send(mass_ship_build_heavy(times))
27 |
28 | @on_command('特型舰建造', permission=GROUP_MEMBER | SUPERUSER)
29 | async def aircraft_build_host(session: CommandSession):
30 | times = session.get('times')
31 | await session.send(mass_ship_build_aircraft(times))
32 |
33 | @light_build_host.args_parser
34 | @heavy_build_host.args_parser
35 | @aircraft_build_host.args_parser
36 | async def build_command_arg_parse(session: CommandSession):
37 | argsStripped = session.current_arg_text.strip(' \n次')
38 |
39 | if argsStripped:
40 | try:
41 | times = int(argsStripped)
42 | assert 0 < times < 11
43 | session.state['times'] = times
44 | except ValueError:
45 | session.finish('?')
46 | except AssertionError:
47 | session.finish('次数太多啦~')
48 | else:
49 | session.state['times'] = 10 #default
50 |
--------------------------------------------------------------------------------
/plugins/azurlane_buildship_simulator/constants.py:
--------------------------------------------------------------------------------
1 | # source of probabilities:
2 | # https://wiki.biligame.com/blhx/%E5%BB%BA%E9%80%A0%E6%A8%A1%E6%8B%9F%E5%99%A8
3 |
4 | SHIP_LIST = {
5 | 'light': {
6 | 'super_rare': ['圣地亚哥', '蒙彼利埃', '贝尔法斯特', '天狼星', '确捷', '雪风', '明石', 'Z46', '阿芙乐尔', '凯旋', '恶毒', '江风'],
7 | 'elite': ['莫里', '拉菲', '圣路易斯', '小海伦娜', '丹佛', '小克利夫兰', '标枪', '无敌', '欧若拉', '谢菲尔德', '小贝法', '黑太子', '吹雪', '绫波', '野分', '夕张', '最上', '三隈', 'Z23', 'Z25', 'Z35', '长春', '太原', '逸仙', '宁海', '平海', '鲁莽', '倔强', '春月', '宵月', '花月', '长波'],
8 | 'rare': ['哈曼', '弗莱彻', '贝奇', '斯坦利', '布什', '黑泽伍德', '斯莫利', '霍比', '科尔克', '康克德', '孟菲斯', '布鲁克林', '菲尼克斯', '亚特兰大', '朱诺', '女将', '阿卡司塔', '热心', '丘比特', '泽西', '库拉索', '杓鹬', '阿基里斯', '阿贾克斯', '南安普顿', '格拉斯哥', '牙买加', '神风', '松风', '旗风', '长月', '初春', '若叶', '初霜', '有明', '夕暮', '大潮', '荒潮', '浦风', '矶风', '谷风', 'Z18', 'Z19', '清波', '莱比锡', '福尔班', '勒马尔', '文月', '朝潮', '滨风', '那珂'],
9 | 'normal': ['卡辛', '唐斯', '克雷文', '麦考尔', '富特', '斯彭斯', '奥利克', '奥马哈', '罗利', '小猎兔犬', '大斗犬', '彗星', '新月', '小天鹅', '狐提', '利安得', '睦月', '如月', '卯月', '长良', '柯尼斯堡', '卡尔斯鲁厄', '科隆']
10 | },
11 | 'heavy': {
12 | 'super_rare': ['明尼阿波利斯', '北卡罗来纳', '华盛顿', '胡德', '厌战', '威尔士亲王', '约克公爵', '高雄', '爱宕', '欧根亲王', '提尔比茨', '让·巴尔', '马萨诸塞', '长门', '三笠', '天城', '加贺BB', '土佐'],
13 | 'elite': ['休斯敦', '印第安纳波利斯', '威奇塔', '亚利桑那', '科罗拉多', '马里兰', '伦敦', '多塞特郡', '约克', '埃克塞特', '足柄', '声望', '伊丽莎白女王', '纳尔逊', '罗德尼', '黑暗界', '恐怖', '阿贝克隆比', '雾岛', '德意志', '斯佩伯爵海军上将', '希佩尔海军上将', '小比叡', '敦刻尔克', '铃谷', '比叡'],
14 | 'rare': ['北安普敦', '芝加哥', '波特兰', '宾夕法尼亚', '田纳西', '加利福尼亚', '什罗普郡', '苏塞克斯', '肯特', '萨福克', '诺福克', '反击', '伊势', '日向'],
15 | 'normal': ['彭萨科拉', '内华达', '俄克拉荷马', '青叶', '衣笠']
16 | },
17 | 'aircraft': {
18 | 'super_rare': ['企业', '埃塞克斯', '半人马', '胜利', '光辉', '翔鹤', '瑞鹤', '大凤', '伊19', '明石', 'U-81', '齐柏林伯爵', 'U-47', 'U-101', '伊168', '香格里拉', '伊13'],
19 | 'elite': ['休斯敦', '印第安纳波利斯', '威奇塔', '列克星敦', '萨拉托加', '约克城', '大黄蜂', '鲦鱼', '女灶神', '伦敦', '多塞特郡', '独角兽', '追赶者', '皇家方舟', '光荣', '伊26', '伊58', 'U-557', '小赤城', '小齐柏林', '絮库夫', '伊25', 'U-522', '伊56'],
20 | 'rare': ['北安普敦', '芝加哥', '波特兰', '长岛', '什罗普郡', '肯特', '萨福克', '诺福克'],
21 | 'normal': ['彭萨科拉', '博格', '兰利', '突击者', '竞技神']
22 | }
23 | }
24 |
25 | # below are CUMULATIVE probabilities out of 100
26 | # order: super_rare, elite, rare, normal
27 | SHIP_CUML_PROB = {
28 | 'light': [7, 19, 45, 100],
29 | 'heavy': [7, 19, 70, 100],
30 | 'aircraft': [7, 19, 70, 100]
31 | }
32 |
--------------------------------------------------------------------------------
/plugins/azurlane_buildship_simulator/simulator.py:
--------------------------------------------------------------------------------
1 | import random
2 | from typing import Dict, List
3 |
4 | from .constants import *
5 |
6 | __all__ = ['mass_ship_build_light',
7 | 'mass_ship_build_heavy',
8 | 'mass_ship_build_aircraft']
9 |
10 |
11 | def mass_ship_build(build_list: Dict[str, List[str]],
12 | cuml: List[int],
13 | times: int) -> str:
14 | '''probabilities is a tuple(list) of four (last one is always 100) integers,
15 | corresponding to the official game'''
16 | resList = []
17 |
18 | for _ in range(times):
19 | randomed: int = random.randint(1, 100)
20 | if 1 <= randomed <= cuml[0]:
21 | resList.append(
22 | '*SSS* ' + random.choice(build_list['super_rare']))
23 | elif cuml[0] < randomed <= cuml[1]:
24 | resList.append(
25 | '*S* ' + random.choice(build_list['elite']))
26 | elif cuml[1] < randomed <= cuml[2]:
27 | resList.append(
28 | random.choice(build_list['rare']))
29 | else:
30 | resList.append(
31 | random.choice(build_list['normal']))
32 | return '\n'.join(resList)
33 |
34 | def mass_ship_build_light(times: int) -> str:
35 | return mass_ship_build(SHIP_LIST['light'], SHIP_CUML_PROB['light'], times)
36 |
37 | def mass_ship_build_heavy(times: int) -> str:
38 | return mass_ship_build(SHIP_LIST['heavy'], SHIP_CUML_PROB['heavy'], times)
39 |
40 | def mass_ship_build_aircraft(times: int) -> str:
41 | return mass_ship_build(SHIP_LIST['aircraft'], SHIP_CUML_PROB['aircraft'], times)
42 |
--------------------------------------------------------------------------------
/plugins/baidutrend/__init__.py:
--------------------------------------------------------------------------------
1 | from nonebot import CommandSession, on_command
2 | from nonebot.permission import *
3 |
4 | from utils_bot.command_ops import global_cooldown
5 | from utils_bot.logging import logger
6 |
7 | from .data_source import get_baidu_trend
8 |
9 | __plugin_name__ = '百度热搜'
10 | __plugin_usage__ = r'''feature: 百度热搜获取
11 |
12 | 百度热搜 获取前6条热搜
13 | 参数:
14 | all 获取全部热搜
15 | '''
16 |
17 |
18 | @on_command('百度热搜', aliases=('百度热点', '时事新闻'), permission=SUPERUSER | GROUP_MEMBER)
19 | @global_cooldown(40)
20 | async def trend(session: CommandSession):
21 | arg = session.get('arg')
22 | trendReport = await get_baidu_trend(arg) # arg passed to function get_baidu_trend
23 | await session.send(trendReport)
24 | logger.info(f'Baidu trend called: {trendReport[32:37]}...')
25 |
26 | @trend.args_parser
27 | async def _(session: CommandSession):
28 | paramStr = session.current_arg_text
29 | # if arg list is not empty
30 | if paramStr:
31 | session.state['arg'] = paramStr.strip()
32 | else:
33 | session.state['arg'] = ''
34 |
--------------------------------------------------------------------------------
/plugins/baidutrend/data_source.py:
--------------------------------------------------------------------------------
1 | import aiohttp
2 | import bs4 # and lxml
3 |
4 | from utils_bot.datetime import TZ, datetime
5 | from utils_bot.logging import logger
6 |
7 |
8 | # gets current time
9 | def getTime() -> str:
10 | return datetime.now(TZ).strftime('%m-%d %H:%M:%S')
11 |
12 | # a page that always works for the program purpose
13 | url: str = "https://www.baidu.com/s?wd=sousuoredian"
14 | headers: dict = {
15 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
16 | # 'Cookie': 'sometimes you need this'
17 | }
18 |
19 | async def get_baidu_trend(opt: str) -> str:
20 | try:
21 | async with aiohttp.ClientSession() as session:
22 | res = await session.get(url, headers=headers, timeout=3)
23 | res.raise_for_status()
24 | soup = bs4.BeautifulSoup(await res.read(), features='lxml')
25 |
26 | titles = soup.select('a.opr-toplist1-subtitle') #|
27 | #pops = soup.select('.opr-toplist1-right') #| place for updates
28 | length = len(titles)
29 |
30 | if opt != 'all':
31 | length = 6
32 |
33 | res = ' NEWS\n'
34 | for j in range(length):
35 | res += titles[j].getText().strip() + '\n'
36 | res += 'fetched %s with love. Source: www.baidu.com' % getTime()
37 | return res
38 | except Exception as e:
39 | logger.exception(e)
40 | return 'an error occurred'
41 |
--------------------------------------------------------------------------------
/plugins/custom_reply/__init__.py:
--------------------------------------------------------------------------------
1 | import json
2 | import random
3 | import re
4 | from os import path
5 |
6 | import asyncio
7 |
8 | from aiocqhttp import Event
9 | from nonebot import CommandSession, get_bot, on_command
10 | from nonebot.permission import *
11 |
12 | from utils_bot.command_ops import force_private
13 | from utils_bot.logging import logger
14 | from utils_bot.typing import Union
15 |
16 |
17 | FAILED_MSG = '查看关键字对:view [群号] [模式]\n'\
18 | '添加单条消息:add [群号] [模式]\n'\
19 | '删除单条消息:del [群号] [模式]\n'\
20 | '删除指定群:delall [群号]\n'\
21 | '模式:完全匹配-1,包含匹配-2,正则匹配-3'
22 |
23 | __plugin_name__ = '自定义群聊回复 (private)'
24 | __plugin_usage__ = r'''feature: 自定义回复
25 |
26 | 从 json 文件读取自定义回复并且响应群聊。
27 | 可以私聊机器人添加或删除机器人,其改变即时生效
28 | ''' + FAILED_MSG
29 |
30 | # define reply data file path
31 | DATA_PATH = path.join(path.dirname(__file__), 'group_data.json')
32 |
33 | DEFAULT_GROUP_DICT: dict = {
34 | "full_match": {},
35 | "inclusive_match": {},
36 | "regex_match" : {}
37 | }
38 |
39 | def load_data() -> dict:
40 | if not path.exists(DATA_PATH):
41 | with open(DATA_PATH, 'w') as datafile:
42 | json.dump({
43 | "global": DEFAULT_GROUP_DICT
44 | }, datafile, indent=4)
45 | with open(DATA_PATH) as datafile:
46 | return json.load(datafile)
47 |
48 | # load reply data
49 | REPLIES: dict = load_data()
50 |
51 | # acquires global event monitor
52 | bot = get_bot()
53 |
54 | # auto reply in group chats
55 |
56 | def process_var(ctx: Event, myText: str) -> str:
57 | 'process whether the reply keyword contains variables.'
58 | if not re.search(r'{SENDER_.+]', myText):
59 | return myText
60 | # define pointer constants
61 | SENDER_ID: str = str(ctx['sender']['user_id'])
62 | SENDER_NICK: str = ctx['sender']['nickname']
63 | SENDER_CARD: str = ctx['sender']['card']
64 | SENDER_ROLE: str = ctx['sender']['role']
65 | SENDER_TITLE: str = ctx['sender']['title']
66 | # when you chose python, you gave up efficiency...
67 | return myText.replace('{SENDER_ID]', SENDER_ID).\
68 | replace('{SENDER_NICK]', SENDER_NICK).\
69 | replace('{SENDER_CARD]', SENDER_CARD).\
70 | replace('{SENDER_ROLE]', SENDER_ROLE).\
71 | replace('{SENDER_TITLE]', SENDER_TITLE)
72 |
73 | class _Get_Out(Exception):
74 | pass
75 |
76 | @bot.on_message('group')
77 | async def handle_keyword_reply(ctx: Event):
78 |
79 | currentGroupId: int = ctx['group_id']
80 | textReceived: str = ctx['raw_message']
81 | toSend: Union[str, None] = None
82 |
83 | # config specific to groups is prioritized
84 | for groupId in (str(currentGroupId), 'global'):
85 | try:
86 | # handles full_match
87 | mayReply = REPLIES[groupId]['full_match'].get(textReceived, None)
88 | if mayReply is not None:
89 | toSend = process_var(ctx, random.choice(mayReply))
90 | raise _Get_Out
91 | # handles inclusive_match
92 | for keyword, reply in REPLIES[groupId]['inclusive_match'].items():
93 | if keyword in textReceived:
94 | toSend = process_var(ctx, random.choice(reply))
95 | raise _Get_Out
96 | # handles regex_match
97 | for keyword, reply in REPLIES[groupId]['regex_match'].items():
98 | if re.search(keyword, textReceived):
99 | toSend = process_var(ctx, random.choice(reply))
100 | raise _Get_Out
101 | except KeyError:
102 | # REPLIES[str(groupId)] may not exist, go to global
103 | pass
104 | except _Get_Out:
105 | break
106 | if toSend is not None:
107 | # waits few secs before sending message
108 | await asyncio.sleep(random.randint(1,5))
109 | await bot.send_group_msg(group_id=currentGroupId, message=toSend)
110 |
111 |
112 | # superuser can modify replies
113 |
114 | class keyword_ops:
115 | 'operations on keyword dict'
116 | def __init__(self, repliesDict,
117 | order='', groupId='', mode='', keyword='', reply=''):
118 | """
119 | :param order: 'add', 'del', 'delall' or 'view'
120 | :param groupId: digits or 'global'
121 | :param mode: '1', '2' or '3'
122 | :param keyword: keyword
123 | :param reply: reply
124 | """
125 | if order not in ('add', 'del', 'delall', 'view'):
126 | raise Exception("指令错误\n" + FAILED_MSG)
127 | if not groupId.isdecimal() and groupId != 'global':
128 | raise Exception("群号错误\n" + FAILED_MSG)
129 | if order != 'delall':
130 | if mode == '1':
131 | self.modeStr: str = 'full_match'
132 | elif mode == '2':
133 | self.modeStr: str = 'inclusive_match'
134 | elif mode == '3':
135 | self.modeStr: str = 'regex_match'
136 | else:
137 | raise Exception("模式错误\n" + FAILED_MSG)
138 |
139 | from copy import deepcopy
140 | self.repliesDict: dict = deepcopy(repliesDict)
141 | self.order: str = order
142 | self.groupId: str = groupId
143 | self.mode: str = mode
144 | self.keyword: str = keyword
145 | self.reply: str = reply
146 |
147 | def add(self):
148 | self.repliesDict.setdefault(self.groupId, DEFAULT_GROUP_DICT)
149 | modifyPlace = self.repliesDict[self.groupId][self.modeStr]
150 | modifyPlace.setdefault(self.keyword, [])
151 | modifyPlace[self.keyword].append(self.reply)
152 |
153 | def dele(self):
154 | del self.repliesDict[self.groupId][self.modeStr][self.keyword]
155 |
156 | def delall(self):
157 | if self.groupId == 'global':
158 | self.repliesDict['global'] = DEFAULT_GROUP_DICT
159 | else:
160 | del self.repliesDict[self.groupId]
161 |
162 | @staticmethod
163 | def backup():
164 | from shutil import copyfile
165 | copyfile(DATA_PATH, path.join(path.dirname(__file__), 'group_data_bak.json'))
166 |
167 | def rewrite(self):
168 | with open(DATA_PATH, 'w') as datafile:
169 | json.dump(self.repliesDict, datafile, indent=4, ensure_ascii=False)
170 |
171 | def send(self):
172 | return self.repliesDict
173 |
174 | def view_keywords(self) -> str:
175 | 'NOTHROW. returns the keyword pairs for group --> mode'
176 | try:
177 | pos: dict = self.repliesDict[self.groupId][self.modeStr]
178 | res: str = f'{self.groupId}, {self.modeStr}\n'
179 | for k, v in pos.items():
180 | if len(v) > 10:
181 | v = v[:10] + ['...']
182 | res += '"{}": "{}"\n'.format(k, '"; "'.join(v))
183 | if pos == {}:
184 | res += '(空)'
185 | res = res.rstrip('\n')
186 | except KeyError:
187 | res = '群号错误?'
188 | return res
189 |
190 | def modify_keywords(self) -> dict:
191 | 'modifies the keyword json file, returns the new keyword dict'
192 | try:
193 | if self.order == 'add':
194 | self.add()
195 | elif self.order == 'del':
196 | self.dele()
197 | elif self.order == 'delall':
198 | self.delall()
199 | except KeyError:
200 | raise Exception('当前关键字表不可用或无此关键字')
201 |
202 | try:
203 | self.backup()
204 | except Exception as exc:
205 | raise Exception('出现错误。 当前设置没有改动' + str(exc))
206 | self.rewrite()
207 |
208 | return self.send()
209 |
210 |
211 | # keyword interface
212 | @on_command('群关键字', permission=SUPERUSER)
213 | @force_private
214 | async def keyword_mod(session: CommandSession):
215 |
216 | order, groupId, mode = '', '', ''
217 | iniParam: list = session.get('iniParam')
218 | try:
219 | order = iniParam[0]
220 | groupId = iniParam[1]
221 | mode = iniParam[2]
222 | except Exception:
223 | pass
224 | logger.info(f'keyword modification called: {order}; {groupId}; {mode}')
225 | ##################################################################
226 |
227 | global REPLIES
228 |
229 | # get keyword mod object, reuse if this command is recalled and continued
230 | if not session.state.get('keymod_obj'):
231 | try:
232 | keymod = keyword_ops(REPLIES, order, groupId, mode)
233 | session.state['keymod_obj'] = keymod
234 | except Exception as exc:
235 | session.finish(str(exc))
236 | else:
237 | keymod = session.state['keymod_obj']
238 | # VIEW order
239 | if order == 'view':
240 | session.finish(keymod.view_keywords())
241 | # MODIFY order
242 | if order in ['add', 'del']:
243 | keymod.keyword = session.get('keyword', prompt='在这里输入关键字')
244 | if order == 'add':
245 | keymod.reply = session.get('reply', prompt='在这里输入回复')
246 | try:
247 | REPLIES = keymod.modify_keywords()
248 | session.finish('success!')
249 | except Exception as exc:
250 | session.finish(str(exc))
251 |
252 |
253 | @keyword_mod.args_parser
254 | @force_private
255 | async def keyword_mod_arg(session: CommandSession):
256 | argStripped = session.current_arg_text.strip()
257 |
258 | if session.is_first_run:
259 | if argStripped:
260 | session.state['iniParam'] = argStripped.split(' ')
261 | # if no arg given at first
262 | else:
263 | session.finish(FAILED_MSG)
264 | elif session.current_key == 'keyword':
265 | session.state['keyword'] = argStripped
266 | elif session.current_key == 'reply':
267 | session.state['reply'] = argStripped
268 |
--------------------------------------------------------------------------------
/plugins/custom_reply/group_data.json:
--------------------------------------------------------------------------------
1 | {
2 | "modes": {
3 | "full match": 1,
4 | "inclusive match": 2,
5 | "regex match": 3
6 | },
7 | "global": {
8 | "full_match": {
9 | "千堂食咩": [
10 | "梅菜扣肉", "菠萝咕噜肉", "蒜蓉粉丝蒸大虾", "清蒸桂鱼", "腊肠炒荷兰豆",
11 | "菠萝咕噜豆腐", "叉烧肉", "卷肠粉", "冬瓜丸子汤", "白灼虾", "香菇虾仁糯米烧麦",
12 | "菠萝咕佬肉", "酸菜烩牛杂", "蜜汁叉烧包", "白切鸡", "砂锅盐焗鸡", "牛肉河粉",
13 | "葱香豉油鸭腿", "鲜虾肠粉", "香辣炒红薯粉", "蒜蓉粉丝蒸虾", "叉烧肉", "猪脚粉",
14 | "螺蛳粉", "南宁粉饺", "不饿", "人肉叉烧包"
15 | ],
16 | "千堂吃什么" : [
17 | "麻婆豆腐", "辣子鸡丁", "东坡肘子", "豆瓣鲫鱼", "口袋豆腐", "酸菜鱼", "夫妻肺片",
18 | "蚂蚁上树", "叫花鸡", "茄汁肉卷", "鱼香肉丝", "干煸冬笋", "魔芋烧鸭", "锅贴鱼片",
19 | "麻辣肉丁", "鱼香茄饼", "冬菜肉末", "粉蒸鸡", "四川火锅", "重庆火锅", "牛油火锅",
20 | "不饿", "宫保鸡丁", "水煮鱼", "刀削面", "炸酱面", "油泼面", "番茄炒面", "麻酱凉面",
21 | "重庆砂锅米线", "云南过桥米线", "牛肉拉面", "兰州牛肉面", "西红柿鸡蛋面",
22 | "白菜猪肉炖粉条"
23 | ],
24 | "大小姐吃什么" : [
25 | "Coquilles Saint-Jacques", "Baked Camembert", "Moules Marinières", "Buckwheat Crêpes",
26 | "Blanquette de Veau", "Soupe à L'oignon", "Sole Meunière", "Hachis Parmentier",
27 | "Boudin Noir Aux Pommes", "Cheese Soufflé", "Steak Tartare", "Pot-au-feu", "Piperade",
28 | "Magret de Canard", "Garbure", "Cassoulet", "Pan-seared Foie Gras", "Confit de Canard",
29 | "Poulet Basquaise", "Lamprey à la Bordelaise", "Quenelles of Pike with Lobster Sauce",
30 | "Soupe de Poisson à la Rouille", "Gigot D'Agneau Pleureur", "Bouillabaisse"
31 | ],
32 | "早安": [
33 | "早安![\"┗|`O′|┛ 起床了嗷~~"
34 | ],
35 | "晚安": [
36 | "晚安 ( ̄o ̄) . z Z Bye Bye"
37 | ],
38 | "$test_variable": [
39 | "你的QQ: {SENDER_ID]\n你的昵称:{SENDER_NICK]"
40 | ]
41 | },
42 | "inclusive_match": {
43 | },
44 | "regex_match": {
45 | "^[A-Z]{3,4}[-\\._]?[0-9]{3,5}$": [
46 | "?"
47 | ]
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/plugins/evaler/__init__.py:
--------------------------------------------------------------------------------
1 | from nonebot import CommandSession, on_command
2 | from nonebot.permission import *
3 |
4 | from utils_bot.command_ops import global_cooldown
5 | from utils_bot.logging import logger
6 |
7 | from .data_source_glot_run import SUPPORTED_LANGS, code_run_glot
8 |
9 | __plugin_name__ = 'coderunner'
10 | __plugin_usage__ = f'''feature: 执行代码
11 |
12 | run [lang](这里空行)[statements] 执行语句
13 | 支持语言:{', '.join(SUPPORTED_LANGS.keys())}
14 |
15 | 示例:
16 | run python
17 | print(1+1)
18 |
19 | attribution: https://glot.io
20 | '''
21 |
22 |
23 | @on_command('coderunner', aliases=('运行', '编译', 'run', 'exe'), permission=SUPERUSER | GROUP_MEMBER, only_to_me=False)
24 | @global_cooldown(15)
25 | async def coderunner(session: CommandSession):
26 | argsList: tuple = session.get('args')
27 | res = await code_run_glot(argsList[0], argsList[1])
28 | await session.send(res)
29 | logger.info(f'coderunner called: {res[:20]}...')
30 |
31 | @coderunner.args_parser
32 | async def _(session: CommandSession):
33 | argsStripped: str = session.current_arg_text.strip()
34 |
35 | if session.is_first_run:
36 | if argsStripped:
37 | argsList: list = argsStripped.split('\n', 1)
38 | if len(argsList) < 2:
39 | session.finish(__plugin_usage__)
40 |
41 | lang, code = argsList[0].strip().lower(), argsList[1]
42 | # manual correction
43 | if lang == 'py': lang = 'python'
44 | elif lang == 'c++': lang = 'cpp'
45 | elif lang == 'c#': lang = 'csharp'
46 | elif lang == 'js': lang = 'javascript'
47 | elif lang == 'f#': lang = 'fsharp'
48 |
49 | if not lang in SUPPORTED_LANGS.keys():
50 | session.finish('当前语言不支持~')
51 |
52 | session.state['args'] = (lang, code)
53 | else:
54 | session.finish(__plugin_usage__)
55 |
--------------------------------------------------------------------------------
/plugins/evaler/data_source_glot_run.py:
--------------------------------------------------------------------------------
1 | #from aiohttp import request
2 | import aiohttp
3 | from nonebot import get_bot
4 |
5 | from utils_bot.logging import logger
6 | from utils_bot.typing import Union
7 |
8 | # code running api source: https://github.com/prasmussen/glot-run/
9 | # api url and doc: https://glot.io
10 | # get your token there at https://glot.io/account/token
11 | ##
12 | # program attribution: https://github.com/cczu-osa/aki/
13 |
14 | RUN_API_URL_FORMAT: str = 'https://glot.io/run/{}?version=latest'
15 |
16 | TOKEN: str = get_bot().config.GLOT_RUN_TOKEN
17 |
18 | SUPPORTED_LANGS: dict = {
19 | 'assembly': {'ext': 'asm'},
20 | 'bash': {'ext': 'sh'},
21 | 'c': {'ext': 'c'},
22 | 'clojure': {'ext': 'clj'},
23 | 'coffeescript': {'ext': 'coffe'},
24 | 'cpp': {'ext': 'cpp'},
25 | 'csharp': {'ext': 'cs'},
26 | 'erlang': {'ext': 'erl'},
27 | 'fsharp': {'ext': 'fs'},
28 | 'go': {'ext': 'go'},
29 | 'groovy': {'ext': 'groovy'},
30 | 'haskell': {'ext': 'hs'},
31 | 'java': {'ext': 'java', 'name': 'Main'},
32 | 'javascript': {'ext': 'js'},
33 | 'julia': {'ext': 'jl'},
34 | 'kotlin': {'ext': 'kt'},
35 | 'lua': {'ext': 'lua'},
36 | 'perl': {'ext': 'pl'},
37 | 'php': {'ext': 'php'},
38 | 'python': {'ext': 'py'},
39 | 'ruby': {'ext': 'rb'},
40 | 'rust': {'ext': 'rs'},
41 | 'scala': {'ext': 'scala'},
42 | 'swift': {'ext': 'swift'},
43 | 'typescript': {'ext': 'ts'},
44 | }
45 |
46 | headers = {'Authorization': f'Token {TOKEN}'}
47 |
48 | async def fetch(lang: str, code: str) -> Union[dict, None]:
49 | async with aiohttp.ClientSession() as session:
50 | try:
51 | async with session.post(RUN_API_URL_FORMAT.format(lang),
52 | headers=headers, raise_for_status=True, timeout=10,
53 | json={
54 | 'files': [{
55 | 'name': (SUPPORTED_LANGS[lang].get('name', 'main') +
56 | f'.{SUPPORTED_LANGS[lang]["ext"]}'),
57 | 'content': code
58 | }],
59 | 'stdin': '',
60 | 'command': ''
61 | }) as req:
62 | req.raise_for_status()
63 | payload: dict = await req.json()
64 | except Exception as e:
65 | logger.exception(e)
66 | return None
67 |
68 | return payload
69 |
70 | def process_result(payload: Union[dict, None]) -> str:
71 | if payload is None:
72 | return '不可用'
73 | res: str = ''
74 | try:
75 | for k in ('stdout', 'stderr', 'error'):
76 | val = payload.get(k)
77 |
78 | lines: list = val.splitlines()
79 | lines, linesRemain = lines[:15], lines[15:]
80 | out, outRemain = val[:80 * 10], val[80 * 10:]
81 |
82 | isCut = '(输出过长,已截断)\n' if linesRemain or outRemain else ''
83 | Add2End = '' if val or k == 'error' else '\n'
84 | res += f'{k}: {isCut}{out}{Add2End}'
85 |
86 | except Exception:
87 | pass
88 | return res
89 |
90 | async def code_run_glot(lang: str, code: str) -> str:
91 | return process_result(await fetch(lang, code))
92 |
--------------------------------------------------------------------------------
/plugins/exec.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import pprint
3 | from typing import Awaitable
4 |
5 | from nonebot import CommandSession, on_command
6 | from nonebot.message import unescape
7 | from nonebot.permission import *
8 |
9 | from utils_bot.command_ops import force_private
10 |
11 | __plugin_name__ = '远程执行 python (private)'
12 | __plugin_usage__ = f'''feature: 执行代码
13 | (根目录:bot.py文件所在目录)
14 | remote [statements]
15 | '''
16 | # source: https://github.com/cczu-osa/aki/
17 |
18 |
19 | @on_command('remote', permission=SUPERUSER)
20 | @force_private
21 | async def _(session: CommandSession):
22 | code = unescape(session.current_arg or '')
23 |
24 | try:
25 | localArgs = {}
26 | exec(code, None, localArgs)
27 | await session.send(f'Locals:\n{pprint.pformat(localArgs, indent=2)}')
28 |
29 | if callable(localArgs.get('run')):
30 | res = localArgs['run'](session.bot, session.event)
31 | if isinstance(res, Awaitable):
32 | res = await asyncio.wait_for(res, 6)
33 | await session.send(f'返回:\n{pprint.pformat(res, indent=2)}')
34 | except Exception as exc:
35 | await session.send(f'执行失败\n异常:\n{pprint.pformat(exc, indent=2)}')
36 |
--------------------------------------------------------------------------------
/plugins/gamble/__init__.py:
--------------------------------------------------------------------------------
1 | from jieba import posseg
2 | from nonebot import (CommandSession, IntentCommand, NLPSession, on_command,
3 | on_natural_language)
4 | from nonebot.permission import *
5 |
6 | from utils_bot.typing import Callable, Generator, Union
7 |
8 | from .diceroll import *
9 |
10 | __plugin_name__ = '试试人品 *NL'
11 | __plugin_usage__ = f'''feature: 生成随机数
12 | 可用命令:
13 | 扔骰子, 扔骰子 []次
14 | 扔硬币, 扔硬币 []次
15 | '''
16 |
17 | # help session
18 | @on_command('试试人品', permission=GROUP_MEMBER | SUPERUSER)
19 | async def try_luck(session: CommandSession):
20 | await session.send(__plugin_usage__)
21 |
22 | class random_ops:
23 | @staticmethod
24 | async def evaluate(session: CommandSession, f: Callable):
25 | times: int = session.get('times')
26 | await session.send(f(**( {'times': times} if times else {} )))
27 |
28 | @staticmethod
29 | def nl_proc(session: NLPSession) -> Generator[Union[str, None], None, None]:
30 | argsStripped: str = session.msg_text.strip()
31 | words = posseg.lcut(argsStripped)
32 |
33 | for word in words:
34 | if word.flag == 'm':
35 | yield word.word
36 | yield None
37 |
38 | @on_command('扔骰子', aliases=('扔色子', '扔个骰子', '扔个色子'), permission=GROUP_MEMBER | SUPERUSER)
39 | async def roll_dice_host(session: CommandSession):
40 | await random_ops.evaluate(session, roll_dice_many)
41 |
42 |
43 | @on_command('扔硬币', aliases=('扔个硬币', '扔钢镚', '扔个钢蹦'), permission=GROUP_MEMBER | SUPERUSER)
44 | async def flip_coin_host(session: CommandSession):
45 | await random_ops.evaluate(session, flip_coin_many)
46 |
47 |
48 |
49 | @roll_dice_host.args_parser
50 | @flip_coin_host.args_parser
51 | async def _(session: CommandSession):
52 | argsStripped: str = session.current_arg_text.strip(' \n次')
53 | session.state['times'] = argsStripped if argsStripped else None
54 |
55 |
56 | # EXP
57 | @on_natural_language(keywords={'骰子', '色子'}, permission=SUPERUSER | GROUP_MEMBER)
58 | async def _(session: NLPSession):
59 | times = next(random_ops.nl_proc(session))
60 | return IntentCommand(64.0, '扔骰子', current_arg=times or '')
61 |
62 | @on_natural_language(keywords={'硬币', '钢镚'}, permission=SUPERUSER | GROUP_MEMBER)
63 | async def _(session: NLPSession):
64 | times = next(random_ops.nl_proc(session))
65 | return IntentCommand(64.0, '扔硬币', current_arg=times or '')
66 |
--------------------------------------------------------------------------------
/plugins/gamble/diceroll.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | from utils_bot.typing import Any
4 |
5 | __all__ = ['roll_dice_many',
6 | 'flip_coin_many']
7 |
8 | DICE_RESULTS = (
9 | '0',
10 | '''
11 | .
12 | /|
13 | |
14 | |
15 | _|_
16 | ''',
17 | '''
18 | .:::.:
19 | .: .:
20 | .::
21 | .::
22 | .::
23 | .:::::::
24 | ''',
25 | r'''
26 | ____
27 | |___ \
28 | __) |
29 | |__ <
30 | ___) |
31 | |____/
32 | ''',
33 | '''
34 | _ _
35 | | || |
36 | | || |_
37 | |__ _|
38 | | |
39 | |_|
40 | ''',
41 | r'''
42 | _____
43 | | ____|
44 | | |__
45 | |___ \
46 | ___) |
47 | |____/
48 | ''',
49 | '''
50 | 666666
51 | 6::::::
52 | 6::::::6
53 | 6::::::6
54 | 6::::::6
55 | 6::::::6
56 | 6::::::6
57 | 6::::::::6666
58 | 6:::::::::::::
59 | 6::::::66666::
60 | 6:::::6 6:
61 | 6:::::6 6:
62 | 6::::::66666::
63 | 66:::::::::::
64 | 66:::::::::
65 | 666666666
66 | ''',
67 | )
68 |
69 | def roll_dice(pixel:bool=False) -> str:
70 | '''displays '1'-'6' randomly. if pixel is true then displays image
71 | '''
72 | res: int = random.randint(1, 6)
73 | if pixel:
74 | return DICE_RESULTS[res].strip()
75 | else:
76 | return str(res)
77 |
78 | def roll_dice_many(times:Any=1) -> str:
79 | 'have to assure [times] is in the form of an int...'
80 | res: str = ''
81 | try:
82 | times = int(times)
83 | if times == 1:
84 | return roll_dice(pixel=True)
85 |
86 | if times > 300000:
87 | raise TimeoutError
88 | resDict = {'1': 0, '2': 0, '3': 0, '4': 0, '5': 0, '6': 0}
89 | for _ in range(times):
90 | r = roll_dice()
91 | resDict[r] += 1
92 | for j in ('1', '2', '3', '4', '5', '6'):
93 | res += f'{j}: {resDict[j]}次\n'
94 | return res.strip()
95 | except TimeoutError:
96 | return '次数太多扔不过来啦~'
97 | except ValueError:
98 | return '?'
99 |
100 |
101 | def flip_coin() -> str:
102 | res: int = random.randint(0, 1)
103 | return ('反', '正')[res]
104 |
105 | def flip_coin_many(times:Any=1) -> str:
106 | 'have to assure [times] is in the form of an int...'
107 | try:
108 | times = int(times)
109 | if times == 1:
110 | return flip_coin()
111 |
112 | if times > 300000:
113 | raise TimeoutError
114 | resList = [0, 0]
115 | for _ in range(times):
116 | r: int = random.randint(0, 1)
117 | resList[r] += 1
118 | return f'正:{resList[1]} 反:{resList[0]}'
119 | except TimeoutError:
120 | return '次数太多扔不过来啦~'
121 | except ValueError:
122 | return '?'
123 |
--------------------------------------------------------------------------------
/plugins/notifyme/__init__.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from apscheduler.job import Job
4 | from nonebot import (CommandSession, IntentCommand, MessageSegment, NLPSession,
5 | get_bot, on_command, on_natural_language, scheduler)
6 | from nonebot.permission import *
7 |
8 | from utils_bot.datetime import TZ, datetime, timedelta
9 | from utils_bot.logging import logger
10 |
11 | __plugin_name__ = '定时提醒 *NL'
12 | __plugin_usage__ = f'''feature: 在XX小时之后提醒用户
13 | 用法:
14 | 定时提醒 [H] [M] [信息] 我将在 H 时 M 分 后在本群发送信息提醒用户
15 | 取消定时提醒 撤销用户在本群设定的定时提醒
16 | '''
17 |
18 | MAX_HOURS = 25
19 |
20 |
21 | def get_job_id(session: CommandSession) -> str:
22 | user = session.event['user_id']
23 | group = session.event.get('group_id', 0)
24 | return f'notifyme_qq{user}_grp{group}'
25 |
26 |
27 | def fmt_job_scheduled_time(job: Job) -> str:
28 | return job.trigger.run_date.strftime('%m月%d日 %H:%M')
29 |
30 |
31 | async def send_notify(user: int, msg: str, group:int=0):
32 | 'group=0 means to send the message to private chat'
33 | bot = get_bot()
34 | if group != 0:
35 | sendmsg = MessageSegment.at(user) + ' ' + msg
36 | await bot.send_group_msg(group_id=group, message=sendmsg)
37 | else:
38 | await bot.send_private_msg(user_id=user, message=msg)
39 | logger.info(f'user {user} finished notifyme job in group {group}')
40 |
41 |
42 | @on_command('定时提醒', aliases=('闹钟'), permission=GROUP_MEMBER | SUPERUSER)
43 | async def notifyme_set(session: CommandSession):
44 | job_id = get_job_id(session)
45 | existing_job = scheduler.get_job(job_id)
46 |
47 | if existing_job:
48 | time = fmt_job_scheduled_time(existing_job)
49 | msg = existing_job.args[1]
50 | session.finish(f'您已有设定的定时提醒~\n{time} {msg} \n告诉我"取消定时提醒"来取消它')
51 |
52 | user, group = session.event['user_id'], session.event.get('group_id', 0)
53 | tdelta = session.get('tdelta')
54 | msg = session.get('msg')
55 |
56 | new_job = scheduler.add_job(send_notify, 'date',
57 | run_date=datetime.now(TZ) + tdelta,
58 | id=job_id,
59 | args=(user, msg, group)
60 | )
61 |
62 | time = fmt_job_scheduled_time(new_job)
63 | msg = new_job.args[1]
64 | await session.send(f'已设定:\n{time} {msg}')
65 | logger.info(f'user {user} finished notifyme job in group {group}')
66 |
67 | @notifyme_set.args_parser
68 | async def _(session: CommandSession):
69 | argsStripped = session.current_arg_text.strip() or ''
70 | args = argsStripped.split(' ', 2)
71 |
72 | if len(args) == 3:
73 | try:
74 | tdelta = timedelta(hours=int(args[0]), minutes=int(args[1]))
75 | if tdelta > timedelta(hours=MAX_HOURS) or tdelta < timedelta():
76 | session.finish(f'最多只能设定到{MAX_HOURS}小时~')
77 | session.state['tdelta'] = tdelta
78 | session.state['msg'] = args[2]
79 | except (ValueError, IndexError):
80 | session.finish(__plugin_usage__)
81 | else:
82 | session.finish(__plugin_usage__)
83 |
84 | @on_natural_language(keywords={'提醒我'}, permission=SUPERUSER | GROUP_MEMBER)
85 | async def _(session: NLPSession):
86 | sentence = session.msg_text.replace('提醒我', '', 1).strip()
87 |
88 | def r(regex):
89 | search = re.findall(regex, sentence)
90 | return search[0] if search != [] else search
91 |
92 | # re.findall(regex,'5小时3分钟后(提醒我)xxxxxyyy')
93 | # -> [('5小时', '5', '小时', '3分钟', '3', '分钟', 'xxxxxyyy')]
94 | search = r(r'((\d+) ?(小?时|h|H))? ?((\d+) ?(分钟?|min))?后?(.+)$')
95 | if len(search) == 7 and (search[1] or search[4]):
96 | return IntentCommand(64.0, '定时提醒', current_arg=f'{search[1] or 0} {search[4] or 0} {search[6]}')
97 | # re.findall(regex, '13:42后xxxx')
98 | # -> [('13', '42', 'xxxx')]
99 | search = r(r'(\d{1,2}):(\d{1,2}) ?后(.+)$')
100 | if len(search) == 3:
101 | return IntentCommand(64.0, '定时提醒', current_arg=f'{search[0]} {search[1]} {search[2]}')
102 | # re.findall(regex, '13:42xxxx')
103 | # -> [('13', ':', '42', 'xxxx')]
104 | # TODO: this part is improvable
105 | search = r(r'(\d{2})(:|点)(\d{2}) ?(.+)$')
106 | if len(search) == 4:
107 | now = datetime.now(TZ)
108 | dt = (now.replace(hour=int(search[0]), minute=int(search[2]),
109 | second=0, microsecond=0) - now).total_seconds()
110 | return IntentCommand(64.0, '定时提醒', current_arg=f'0 {int(dt/60)+1} {search[3]}')
111 |
112 | return IntentCommand(0, '定时提醒')
113 |
114 |
115 | @on_command('取消定时提醒', aliases=('撤销定时提醒',), permission=GROUP_MEMBER | SUPERUSER)
116 | async def notifyme_revoke(session: CommandSession):
117 | job = scheduler.get_job(get_job_id(session))
118 | if job:
119 | time = fmt_job_scheduled_time(job)
120 | job.remove()
121 | await session.send(f'已取消预定于 {time} 的定时提醒')
122 | else:
123 | await session.send('您没有设定定时提醒~')
124 |
--------------------------------------------------------------------------------
/plugins/personality/__init__.py:
--------------------------------------------------------------------------------
1 | from nonebot import CommandSession as CmdS
2 | from nonebot.permission import *
3 |
4 | from utils_bot.command_ops import (on_grp_command, on_grp_command_ask,
5 | on_grp_command_do)
6 | from utils_bot.string_ops import half_none, prob_pick
7 |
8 | __plugin_usage__ = '一些个性化回复'
9 |
10 | @on_grp_command_ask('你是谁', '是谁', '谁')
11 | async def _(s: CmdS): await s.send('sendo erika!')
12 |
13 | @on_grp_command_ask('性别', '你的性别')
14 | async def _(s: CmdS): await s.send(f'女{half_none("!")}')
15 |
16 | @on_grp_command_ask('年龄', '你的年龄')
17 | async def _(s: CmdS): await s.send(f'16{half_none("!")}')
18 |
19 | @on_grp_command_ask('主人是谁', '你的主人是谁', '谁是你的主人')
20 | async def _(s: CmdS): await s.send('没有')
21 |
22 | @on_grp_command_ask('你爱我吗', '你爱不爱我', '爱我吗', '爱不爱我')
23 | async def _(s: CmdS): await s.send('想要获得本小姐的青睐,可不是容易的事情噢~')
24 |
25 | @on_grp_command_do('结婚', '嫁给我', '我娶你')
26 | async def _(s: CmdS): await s.send('绝对不行')
27 |
28 | @on_grp_command('我爱你')
29 | async def _(s: CmdS): await s.send('绝对不行')
30 |
31 | # | | | | ?
32 | # v v v v
33 | @on_grp_command_do('娇喘', '淫叫', '叫床')
34 | async def _(s: CmdS):
35 | reply = ('你怎么了?', '哈?', '哈??', '嗯……',
36 | '……怎么突然说这种话',
37 | '…哈……哈…唔嗯…………唔哈哈~……啊啊啊',
38 | '嗯,咯……!啊啊,呀,啊嗯,呷,呼啊,哈……,啊\n——我们,一起!')
39 | prob = (.1, .35, .6, .75, .9, .96, 1)
40 | await s.send(prob_pick(reply, prob))
41 |
--------------------------------------------------------------------------------
/plugins/remotely/__init__.py:
--------------------------------------------------------------------------------
1 | from nonebot import CommandSession, get_bot, load_plugins, on_command
2 | from nonebot.exceptions import CQHttpError
3 | from nonebot.message import unescape
4 | from nonebot.permission import *
5 |
6 | from utils_bot.typing import depreciated
7 |
8 | __plugin_name__ = '遥控机器人 (private)'
9 | __plugin_usage__ = r'''feature: 遥控
10 | 发送消息:
11 | 发送到群 [群号] [内容]
12 | 发送到QQ [QQ号] [内容]
13 |
14 | 发送CQ码:
15 | 发送到群CQ [群号] [内容]
16 | 发送到QQCQ [QQ号] [内容]
17 |
18 | 改群名片:
19 | 改群名片 [群号] [内容 | ''] (内容为空代表删除)
20 |
21 | 查看已加入的群:
22 | 所在的群
23 | '''
24 |
25 | async def send_to_x(session: CommandSession, msg_type: str, unescape_=False):
26 | bot = get_bot()
27 | targetId, toSend = session.get('id'), session.get('msg')
28 | if unescape_:
29 | toSend = unescape(toSend)
30 |
31 | try:
32 | if msg_type == 'group':
33 | await bot.send_group_msg(group_id=targetId, message=toSend)
34 | elif msg_type == 'private':
35 | await bot.send_private_msg(user_id=targetId, message=toSend)
36 | await session.send('success!')
37 | except CQHttpError as exc:
38 | await session.send(str(exc))
39 |
40 | @on_command('发送到群', permission=SUPERUSER, privileged=True)
41 | async def send_to_group(session: CommandSession):
42 | await send_to_x(session, 'group')
43 |
44 | @on_command('发送到QQ', permission=SUPERUSER, privileged=True)
45 | async def send_to_private(session: CommandSession):
46 | await send_to_x(session, 'private')
47 |
48 | @on_command('发送到群CQ', permission=SUPERUSER, privileged=True)
49 | async def send_to_group_CQ(session: CommandSession):
50 | await send_to_x(session, 'group', True)
51 |
52 | @on_command('发送到QQCQ', permission=SUPERUSER, privileged=True)
53 | async def send_to_private_CQ(session: CommandSession):
54 | await send_to_x(session, 'private', True)
55 |
56 | @send_to_group_CQ.args_parser
57 | @send_to_private_CQ.args_parser
58 | @send_to_group.args_parser
59 | @send_to_private.args_parser
60 | async def _(session: CommandSession):
61 | argStripped = session.current_arg.strip() or ''
62 | args = argStripped.split(' ', 1)
63 | if len(args) == 2:
64 | session.state['id'] = args[0]
65 | session.state['msg'] = args[1]
66 | else:
67 | session.finish('用法:\n发送到群/QQ [群号/QQ] [内容]')
68 |
69 |
70 | @on_command('改群名片', permission=SUPERUSER, privileged=True)
71 | async def change_my_group_card(session: CommandSession):
72 | bot = get_bot()
73 | targetId, card = session.get('id'), session.get('card')
74 | try:
75 | await bot.set_group_card(group_id=targetId, user_id=bot.config.SELF_QQ, card=card)
76 | await session.send('success!')
77 | except CQHttpError as exc:
78 | await session.send(str(exc))
79 |
80 | @change_my_group_card.args_parser
81 | async def _(session: CommandSession):
82 | argStripped = session.current_arg.strip() or ''
83 | args = argStripped.split(' ', 1) if argStripped else []
84 | if len(args) >= 1:
85 | session.state['id'] = args[0]
86 | session.state['card'] = args[1] if len(args) >= 2 else ''
87 | else:
88 | session.finish('用法:\n改群名片 [群号] [内容 | ""]')
89 |
90 |
91 | @on_command('所在的群', permission=SUPERUSER, privileged=True)
92 | async def groups_in(session: CommandSession):
93 | groups = await get_bot().get_group_list()
94 | res = ''
95 | for each in groups:
96 | res += f'{each["group_id"]}: {each["group_name"]}\n'
97 | res = res.rstrip('\n')
98 | await session.send(res)
99 |
100 |
101 | @on_command('重置插件', permission=SUPERUSER, privileged=True)
102 | @depreciated
103 | async def reset_plugins(session: CommandSession):
104 | from os import path
105 | load_plugins(path.join('.', 'plugins'), 'plugins')
106 |
--------------------------------------------------------------------------------
/plugins/repeater/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | import asyncio
3 | import random
4 |
5 | from aiocqhttp import Event
6 | from nonebot import get_bot
7 | from nonebot.permission import *
8 |
9 | from utils_bot.msg_ops import msg_is_calling_me
10 | from utils_bot.typing import *
11 |
12 | __plugin_name__ = '复读机 (private)'
13 | __plugin_usage__ = r'''feature: 复读
14 | 人类的本质
15 | '''
16 |
17 | # acquires global event monitor
18 | bot = get_bot()
19 |
20 | class Record:
21 | def __init__(self, lastMsg: str, count: int):
22 | self.lastMsg = lastMsg
23 | self.count = count
24 |
25 | class Records(dict):
26 |
27 | def get_record(self, group_id: str, msg: str) -> Record:
28 | 'creates tracker for each group at beginning'
29 | record = self.get(group_id)
30 | if record is None:
31 | record = Record(msg, 0) # TODO: better semantics
32 | self[group_id] = record
33 | return record
34 |
35 | def simple_repeat(self, group_id: str, msg: str,
36 | wait_until: int = 3) -> Union[str, None]:
37 | # creates tracker for each group at beginning
38 | record = self.get_record(group_id, msg)
39 | if msg != record.lastMsg:
40 | record.lastMsg, record.count = msg, 1
41 | return
42 | record.count += 1
43 | if record.count == wait_until:
44 | record.count = -999
45 | return msg
46 |
47 | def you_repeat(self, group_id: str, msg: str) -> Union[str, None]:
48 | 'used when message starts with "我"'
49 | record = self.get_record(group_id, msg)
50 | if random.choice((0,0,0,0,1)):
51 | if msg_is_calling_me(msg):
52 | return
53 | record.count = -999
54 | newMsg = []
55 | for char in msg:
56 | if char == '我': newMsg.append('你')
57 | elif char == '你': newMsg.append('我')
58 | else: newMsg.append(char)
59 | return ''.join(newMsg)
60 |
61 | # key: str
62 | # value: Record
63 | records = Records()
64 |
65 | @bot.on_message('group')
66 | async def _(ctx: Event):
67 |
68 | groupId = ctx['group_id']
69 | msg = ctx['raw_message']
70 |
71 | ## special: if message starts with '我' then reply with the same sentece but with '你'
72 | if msg.startswith('我'):
73 | sendMsg = records.you_repeat(groupId, msg)
74 | # delayed
75 | if sendMsg is not None:
76 | await asyncio.sleep(random.randint(1, 10))
77 | else:
78 | sendMsg = records.simple_repeat(groupId, msg, 3)
79 | if sendMsg is not None:
80 | await bot.send_group_msg(group_id=groupId, message=sendMsg)
81 |
--------------------------------------------------------------------------------
/plugins/request_handler.py:
--------------------------------------------------------------------------------
1 | from nonebot import NoticeSession, RequestSession, on_notice, on_request
2 |
3 | from utils_bot.msg_ops import SUPERUSERS, send_to_superusers
4 |
5 | __plugin_usage__ = r'''feature: 处理群消息
6 | '''
7 |
8 |
9 |
10 | # accepts group invites only from superusers, instantly
11 | @on_request('group.invite')
12 | async def _(session: RequestSession):
13 | sender = session.event['user_id']
14 | if sender in SUPERUSERS:
15 | await session.approve()
16 | await send_to_superusers(
17 | f'接受了群{session.event["group_id"]}的邀请。(发起人:{sender})')
18 | else:
19 | await session.reject()
20 |
21 |
22 | # notify superusers when bot joins a group
23 | @on_notice('group_increase.invite')
24 | async def _(session: NoticeSession):
25 | if session.event['self_id'] != session.event['user_id']:
26 | return
27 | await send_to_superusers(
28 | f'加入了群{session.event["group_id"]}。')
29 |
30 |
31 | # notify superusers when bot gets kicked from a group
32 | @on_notice('group_decrease.kick_me')
33 | async def _(session: NoticeSession):
34 | if session.event['self_id'] != session.event['user_id']:
35 | return
36 | await send_to_superusers(
37 | f'被群{session.event["group_id"]}踢出了。执行者:{session.event["operator_id"]}')
38 |
39 |
40 | # notify superusers when bot is set admin
41 | @on_notice('group_admin.set')
42 | async def _(session: NoticeSession):
43 | if session.event['self_id'] != session.event['user_id']:
44 | return
45 | await send_to_superusers(
46 | f'被群{session.event["group_id"]}设置为管理员。')
47 |
48 |
49 | # notify superusers when bot is unset admin
50 | @on_notice('group_admin.unset')
51 | async def _(session: NoticeSession):
52 | if session.event['self_id'] != session.event['user_id']:
53 | return
54 | await send_to_superusers(
55 | f'被群{session.event["group_id"]}取消管理员。')
56 |
--------------------------------------------------------------------------------
/plugins/song/__init__.py:
--------------------------------------------------------------------------------
1 | from nonebot import (CommandSession, IntentCommand, MessageSegment, NLPSession,
2 | on_command, on_natural_language)
3 | from nonebot.permission import *
4 |
5 | from utils_bot.command_ops import global_cooldown
6 | from utils_bot.logging import logger
7 |
8 | from .data_source import get_netease_song_id
9 |
10 | __plugin_name__ = '点歌'
11 | __plugin_usage__ = r'''feature: 从网易云分享一首歌曲~
12 |
13 | 点歌 [歌名] 点一首歌
14 | '''
15 |
16 |
17 | @on_command('点歌', permission=SUPERUSER | GROUP_MEMBER)
18 | @global_cooldown(1)
19 | async def share_song(session: CommandSession):
20 | songname: str = session.get('songname')
21 | songid = await get_netease_song_id(songname)
22 | report = MessageSegment.music('163', songid) if songid is not None \
23 | else '未能找到这首歌曲?~'
24 | await session.send(report)
25 | logger.info(f'share song called: {report}...')
26 |
27 | @share_song.args_parser
28 | async def _(session: CommandSession):
29 | argStripped: str = session.current_arg_text.strip()
30 |
31 | if session.is_first_run:
32 | if argStripped:
33 | session.state['songname'] = argStripped
34 | else:
35 | session.finish(__plugin_usage__)
36 |
37 | # also match "点歌xxx" without space in between
38 | @on_natural_language(keywords={'点歌'}, permission=SUPERUSER | GROUP_MEMBER)
39 | async def _(session: NLPSession):
40 | if session.msg_text[:2] == '点歌':
41 | return IntentCommand(64.0, '点歌', current_arg=session.msg_text[2:])
42 | return IntentCommand(0, '点歌')
43 |
--------------------------------------------------------------------------------
/plugins/song/data_source.py:
--------------------------------------------------------------------------------
1 | from urllib.parse import quote_plus
2 |
3 | import aiohttp
4 |
5 | from utils_bot.logging import logger
6 | from utils_bot.typing import Union
7 |
8 | # source: https://github.com/mixmoe/HibiAPI
9 |
10 | URL_FORMAT = 'https://api.obfs.dev/api/netease/search?s={}&search_type=1&limit=1&offset=0'
11 |
12 | headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'}
13 |
14 | async def get_netease_song_id(name: str) -> Union[int, None]:
15 | try:
16 | async with aiohttp.ClientSession() as session:
17 | res = await session.get(URL_FORMAT.format(quote_plus(name)), headers=headers, timeout=10)
18 | res.raise_for_status()
19 | jsn = await res.json()
20 | return jsn['result']['songs'][0]['id']
21 | except Exception as e:
22 | logger.exception(e)
23 | return None
24 |
--------------------------------------------------------------------------------
/plugins/test_rp/__init__.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | from nonebot import CommandSession, on_command
4 | from nonebot.permission import *
5 |
6 | from utils_bot.datetime import TZ, datetime
7 |
8 | __plugin_name__ = '今日运气'
9 | __plugin_usage__ = f'''feature: 看看今天的运气~
10 | 可用命令:运气
11 | 不为结果负责。
12 | '''
13 |
14 | class TestLuck:
15 |
16 | @staticmethod
17 | def return_luck_by_num(num: float) -> str:
18 | if 0.0 <= num < 0.1:
19 | return '极坏'
20 | elif 0.1 <= num < 0.4:
21 | return '坏'
22 | elif 0.4 <= num < 0.7:
23 | return '一般'
24 | elif 0.7 <= num < 0.9:
25 | return '好'
26 | else:
27 | return '极好'
28 |
29 | @classmethod
30 | def generate_luck_result(cls, sender_id: int) -> str:
31 | senderId: int = sender_id
32 | timeStamp: int = int(
33 | datetime.now(TZ).strftime('%m%d%Y')
34 | )
35 | seed: int = (senderId * 2) | (timeStamp * 333)
36 | random.seed(seed)
37 | res: float = random.random()
38 | random.seed()
39 | return cls.return_luck_by_num(res)
40 |
41 | @on_command('我的运气', aliases=('运气', '今日运气', '今日人品', '我的人品', 'jrrp', '运势', '今日运势'), permission=GROUP_MEMBER | SUPERUSER)
42 | async def my_luck_today(session: CommandSession):
43 | senderId: int = int(session.event['user_id'])
44 | await session.send(TestLuck.generate_luck_result(senderId), at_sender=True)
45 |
--------------------------------------------------------------------------------
/plugins/usage.py:
--------------------------------------------------------------------------------
1 | import nonebot
2 | from nonebot import on_command, CommandSession, get_bot
3 | from nonebot.permission import *
4 |
5 | __plugin_name__ = '帮助'
6 | __plugin_usage__ = r'''feature: 帮助
7 |
8 | 帮助 获取帮助
9 | 参数:
10 | [功能名] 获取特定功能的帮助
11 | 例子:
12 | 千堂帮助 google
13 | '''
14 |
15 | @on_command('帮助', aliases=['help', '功能'], permission=SUPERUSER | GROUP_MEMBER)
16 | async def _(session: CommandSession):
17 | # get list of all plugins
18 | if session.event['user_id'] in get_bot().config.SUPERUSERS\
19 | and not session.event.get('group_id') \
20 | and not session.event.get('discuss_id'):
21 | plugins = [p for p in nonebot.get_loaded_plugins() if p.name]
22 | else:
23 | plugins = [p for p in nonebot.get_loaded_plugins() if p.name\
24 | and not p.name.endswith('private)')]
25 |
26 | arg = session.current_arg_text.strip().lower()
27 | if not arg:
28 | text = '呼叫我的名字来使用以下功能~:\n{\n\t' +\
29 | '\n\t'.join(p.name or '(unnamed)' for p in plugins) + '\n}' +\
30 | '例子:帮助 天气'
31 | await session.send(text)
32 |
33 | else:
34 | for p in plugins:
35 | if arg in p.name.lower():
36 | await session.send(p.usage.strip())
37 |
--------------------------------------------------------------------------------
/plugins/weather/__init__.py:
--------------------------------------------------------------------------------
1 | from jieba import posseg
2 | from nonebot import (CommandSession, IntentCommand, NLPSession,
3 | on_command, on_natural_language)
4 | from nonebot.permission import *
5 | from translate import Translator
6 |
7 | from utils_bot.logging import logger
8 |
9 | from .china_city_list_source_amap import CHINESE_CITIES
10 | from .data_source_amap import amap_weather
11 | from .data_source_openweather import openweathermap_weather
12 |
13 | __plugin_name__ = '天气 *NL'
14 | __plugin_usage__ = r'''feature: 查询天气
15 |
16 | 天气 [城市] 获取天气预报
17 | 来源:
18 | CN: AMAP, https://www.amap.com/
19 | EN: openweathermap http://api.openweathermap.org/
20 | '''
21 |
22 | class util:
23 | @staticmethod
24 | def isChinese(word: str) -> bool:
25 | for ch in word:
26 | if '\u4e00' <= ch <= '\u9fff':
27 | return True
28 | return False
29 |
30 | @staticmethod
31 | def isAmapSupported(word: str) -> bool:
32 | return word.rstrip('市') in CHINESE_CITIES
33 |
34 | @staticmethod
35 | def translate2Eng(word: str) -> str:
36 | # LOW EFFICIENCY MANUAL CORRECTION
37 | if word == '雪城': return 'syracuse'
38 |
39 | translator = Translator(from_lang='zh', to_lang='en')
40 | res = translator.translate(word).lower().rstrip(' city')
41 | return res
42 |
43 |
44 | @on_command('weather', aliases=('天气', '天气查询', '查询天气', '查天气'), permission=SUPERUSER | GROUP_MEMBER)
45 | async def weather(session: CommandSession):
46 | city: str = session.get('city')
47 | isChinese: bool = util.isChinese(city)
48 |
49 | # AMAP
50 | if isChinese and util.isAmapSupported(city):
51 | weatherReport = await amap_weather(city)
52 | # OpenWeatherMap (delete block if you do not need)
53 | else:
54 | # openweathermap needs an English city name
55 | city = util.translate2Eng(city) if isChinese else city
56 | weatherReport = await openweathermap_weather(city)
57 |
58 | await session.send(weatherReport)
59 | logger.info(f'weather called: {weatherReport[:100]}...')
60 |
61 | @weather.args_parser
62 | async def _(session: CommandSession):
63 | argStripped: str = session.current_arg_text.strip()
64 |
65 | if session.is_first_run:
66 | if argStripped:
67 | session.state['city'] = argStripped
68 | else:
69 | session.finish(__plugin_usage__)
70 | # EXP
71 | @on_natural_language(keywords={'天气'}, permission=SUPERUSER | GROUP_MEMBER)
72 | async def _(session: NLPSession):
73 | argsStripped = session.msg_text.strip()
74 | words = list(posseg.lcut(argsStripped))
75 |
76 | city = None
77 | for word in words:
78 | if word.flag == 'ns':
79 | city = word.word
80 | break
81 | if city is None:
82 | city = ' '.join((word.word for word in words if word.flag == 'eng'))
83 |
84 | return IntentCommand(64.0, 'weather', current_arg=city or '')
85 |
--------------------------------------------------------------------------------
/plugins/weather/china_city_list_source_amap.py:
--------------------------------------------------------------------------------
1 | from os import path
2 |
3 | with open(path.join(path.dirname(__file__), 'china_city_list_source_amap.txt'), 'r', encoding='utf-8') as f:
4 | CHINESE_CITIES = { line.strip('\n') for line in f }
5 |
--------------------------------------------------------------------------------
/plugins/weather/china_city_list_source_amap.txt:
--------------------------------------------------------------------------------
1 | 中华人民共和国
2 | 北京
3 | 北京
4 | 东城
5 | 西城
6 | 朝阳
7 | 丰台
8 | 石景山
9 | 海淀
10 | 门头沟
11 | 房山
12 | 通州
13 | 顺义
14 | 昌平
15 | 大兴
16 | 怀柔
17 | 平谷
18 | 密云
19 | 延庆
20 | 天津
21 | 天津
22 | 和平
23 | 河东
24 | 河西
25 | 南开
26 | 河北
27 | 红桥
28 | 东丽
29 | 西青
30 | 津南
31 | 北辰
32 | 武清
33 | 宝坻
34 | 滨海新
35 | 宁河
36 | 静海
37 | 蓟州
38 | 河北省
39 | 石家庄
40 | 石家庄
41 | 长安
42 | 桥西
43 | 新华
44 | 井陉矿
45 | 裕华
46 | 藁城
47 | 鹿泉
48 | 栾城
49 | 井陉
50 | 正定
51 | 行唐
52 | 灵寿
53 | 高邑
54 | 深泽
55 | 赞皇
56 | 无极
57 | 平山
58 | 元氏
59 | 赵
60 | 辛集
61 | 晋州
62 | 新乐
63 | 唐山
64 | 唐山
65 | 路南
66 | 路北
67 | 古冶
68 | 开平
69 | 丰南
70 | 丰润
71 | 曹妃甸
72 | 滦州
73 | 滦南
74 | 乐亭
75 | 迁西
76 | 玉田
77 | 遵化
78 | 迁安
79 | 秦皇岛
80 | 秦皇岛
81 | 海港
82 | 山海关
83 | 北戴河
84 | 抚宁
85 | 青龙满族
86 | 昌黎
87 | 卢龙
88 | 邯郸
89 | 邯郸
90 | 邯山
91 | 丛台
92 | 复兴
93 | 峰峰矿
94 | 肥乡
95 | 永年
96 | 临漳
97 | 成安
98 | 大名
99 | 涉
100 | 磁
101 | 邱
102 | 鸡泽
103 | 广平
104 | 馆陶
105 | 魏
106 | 曲周
107 | 武安
108 | 邢台
109 | 邢台
110 | 桥东
111 | 桥西
112 | 邢台
113 | 临城
114 | 内丘
115 | 柏乡
116 | 隆尧
117 | 任
118 | 南和
119 | 宁晋
120 | 巨鹿
121 | 新河
122 | 广宗
123 | 平乡
124 | 威
125 | 清河
126 | 临西
127 | 南宫
128 | 沙河
129 | 保定
130 | 保定
131 | 竞秀
132 | 莲池
133 | 满城
134 | 清苑
135 | 徐水
136 | 涞水
137 | 阜平
138 | 定兴
139 | 唐
140 | 高阳
141 | 容城
142 | 涞源
143 | 望都
144 | 安新
145 | 易
146 | 曲阳
147 | 蠡
148 | 顺平
149 | 博野
150 | 雄
151 | 涿州
152 | 定州
153 | 安国
154 | 高碑店
155 | 张家口
156 | 张家口
157 | 桥东
158 | 桥西
159 | 宣化
160 | 下花园
161 | 万全
162 | 崇礼
163 | 张北
164 | 康保
165 | 沽源
166 | 尚义
167 | 蔚
168 | 阳原
169 | 怀安
170 | 怀来
171 | 涿鹿
172 | 赤城
173 | 承德
174 | 承德
175 | 双桥
176 | 双滦
177 | 鹰手营子矿
178 | 承德
179 | 兴隆
180 | 滦平
181 | 隆化
182 | 丰宁满族
183 | 宽城满族
184 | 围场满族蒙古族
185 | 平泉
186 | 沧州
187 | 沧州
188 | 新华
189 | 运河
190 | 沧
191 | 青
192 | 东光
193 | 海兴
194 | 盐山
195 | 肃宁
196 | 南皮
197 | 吴桥
198 | 献
199 | 孟村回族
200 | 泊头
201 | 任丘
202 | 黄骅
203 | 河间
204 | 廊坊
205 | 廊坊
206 | 安次
207 | 广阳
208 | 固安
209 | 永清
210 | 香河
211 | 大城
212 | 文安
213 | 大厂回族
214 | 霸州
215 | 三河
216 | 衡水
217 | 衡水
218 | 桃城
219 | 冀州
220 | 枣强
221 | 武邑
222 | 武强
223 | 饶阳
224 | 安平
225 | 故城
226 | 景
227 | 阜城
228 | 深州
229 | 山西省
230 | 太原
231 | 太原
232 | 小店
233 | 迎泽
234 | 杏花岭
235 | 尖草坪
236 | 万柏林
237 | 晋源
238 | 清徐
239 | 阳曲
240 | 娄烦
241 | 古交
242 | 大同
243 | 大同
244 | 平城
245 | 云冈
246 | 新荣
247 | 阳高
248 | 天镇
249 | 广灵
250 | 灵丘
251 | 浑源
252 | 左云
253 | 云州
254 | 阳泉
255 | 阳泉
256 | 城
257 | 矿
258 | 郊
259 | 平定
260 | 盂
261 | 长治
262 | 长治
263 | 潞州
264 | 上党
265 | 襄垣
266 | 屯留
267 | 平顺
268 | 黎城
269 | 壶关
270 | 长子
271 | 武乡
272 | 沁
273 | 沁源
274 | 潞城
275 | 晋城
276 | 晋城
277 | 城
278 | 沁水
279 | 阳城
280 | 陵川
281 | 泽州
282 | 高平
283 | 朔州
284 | 朔州
285 | 朔城
286 | 平鲁
287 | 山阴
288 | 应
289 | 右玉
290 | 怀仁
291 | 晋中
292 | 晋中
293 | 榆次
294 | 榆社
295 | 左权
296 | 和顺
297 | 昔阳
298 | 寿阳
299 | 太谷
300 | 祁
301 | 平遥
302 | 灵石
303 | 介休
304 | 运城
305 | 运城
306 | 盐湖
307 | 临猗
308 | 万荣
309 | 闻喜
310 | 稷山
311 | 新绛
312 | 绛
313 | 垣曲
314 | 夏
315 | 平陆
316 | 芮城
317 | 永济
318 | 河津
319 | 忻州
320 | 忻州
321 | 忻府
322 | 定襄
323 | 五台
324 | 代
325 | 繁峙
326 | 宁武
327 | 静乐
328 | 神池
329 | 五寨
330 | 岢岚
331 | 河曲
332 | 保德
333 | 偏关
334 | 原平
335 | 临汾
336 | 临汾
337 | 尧都
338 | 曲沃
339 | 翼城
340 | 襄汾
341 | 洪洞
342 | 古
343 | 安泽
344 | 浮山
345 | 吉
346 | 乡宁
347 | 大宁
348 | 隰
349 | 永和
350 | 蒲
351 | 汾西
352 | 侯马
353 | 霍州
354 | 吕梁
355 | 吕梁
356 | 离石
357 | 文水
358 | 交城
359 | 兴
360 | 临
361 | 柳林
362 | 石楼
363 | 岚
364 | 方山
365 | 中阳
366 | 交口
367 | 孝义
368 | 汾阳
369 | 内蒙古
370 | 呼和浩特
371 | 呼和浩特
372 | 新城
373 | 回民
374 | 玉泉
375 | 赛罕
376 | 土默特左旗
377 | 托克托
378 | 和林格尔
379 | 清水河
380 | 武川
381 | 包头
382 | 包头
383 | 东河
384 | 昆都仑
385 | 青山
386 | 石拐
387 | 白云鄂博矿
388 | 九原
389 | 土默特右旗
390 | 固阳
391 | 达尔罕茂明安联合旗
392 | 乌海
393 | 乌海
394 | 海勃湾
395 | 海南
396 | 乌达
397 | 赤峰
398 | 赤峰
399 | 红山
400 | 元宝山
401 | 松山
402 | 阿鲁科尔沁旗
403 | 巴林左旗
404 | 巴林右旗
405 | 林西
406 | 克什克腾旗
407 | 翁牛特旗
408 | 喀喇沁旗
409 | 宁城
410 | 敖汉旗
411 | 通辽
412 | 通辽
413 | 科尔沁
414 | 科尔沁左翼中旗
415 | 科尔沁左翼后旗
416 | 开鲁
417 | 库伦旗
418 | 奈曼旗
419 | 扎鲁特旗
420 | 霍林郭勒
421 | 鄂尔多斯
422 | 鄂尔多斯
423 | 东胜
424 | 康巴什
425 | 达拉特旗
426 | 准格尔旗
427 | 鄂托克前旗
428 | 鄂托克旗
429 | 杭锦旗
430 | 乌审旗
431 | 伊金霍洛旗
432 | 呼伦贝尔
433 | 呼伦贝尔
434 | 海拉尔
435 | 扎赉诺尔
436 | 阿荣旗
437 | 莫力达瓦达斡尔族旗
438 | 鄂伦春旗
439 | 鄂温克族旗
440 | 陈巴尔虎旗
441 | 新巴尔虎左旗
442 | 新巴尔虎右旗
443 | 满洲里
444 | 牙克石
445 | 扎兰屯
446 | 额尔古纳
447 | 根河
448 | 巴彦淖尔
449 | 巴彦淖尔
450 | 临河
451 | 五原
452 | 磴口
453 | 乌拉特前旗
454 | 乌拉特中旗
455 | 乌拉特后旗
456 | 杭锦后旗
457 | 乌兰察布
458 | 乌兰察布
459 | 集宁
460 | 卓资
461 | 化德
462 | 商都
463 | 兴和
464 | 凉城
465 | 察哈尔右翼前旗
466 | 察哈尔右翼中旗
467 | 察哈尔右翼后旗
468 | 四子王旗
469 | 丰镇
470 | 兴安盟
471 | 乌兰浩特
472 | 阿尔山
473 | 科尔沁右翼前旗
474 | 科尔沁右翼中旗
475 | 扎赉特旗
476 | 突泉
477 | 锡林郭勒盟
478 | 二连浩特
479 | 锡林浩特
480 | 阿巴嘎旗
481 | 苏尼特左旗
482 | 苏尼特右旗
483 | 东乌珠穆沁旗
484 | 西乌珠穆沁旗
485 | 太仆寺旗
486 | 镶黄旗
487 | 正镶白旗
488 | 正蓝旗
489 | 多伦
490 | 阿拉善盟
491 | 阿拉善左旗
492 | 阿拉善右旗
493 | 额济纳旗
494 | 辽宁省
495 | 沈阳
496 | 沈阳
497 | 和平
498 | 沈河
499 | 大东
500 | 皇姑
501 | 铁西
502 | 苏家屯
503 | 浑南
504 | 沈北新
505 | 于洪
506 | 辽中
507 | 康平
508 | 法库
509 | 新民
510 | 大连
511 | 大连
512 | 中山
513 | 西岗
514 | 沙河口
515 | 甘井子
516 | 旅顺口
517 | 金州
518 | 普兰店
519 | 长海
520 | 瓦房店
521 | 庄河
522 | 鞍山
523 | 鞍山
524 | 铁东
525 | 铁西
526 | 立山
527 | 千山
528 | 台安
529 | 岫岩满族
530 | 海城
531 | 抚顺
532 | 抚顺
533 | 新抚
534 | 东洲
535 | 望花
536 | 顺城
537 | 抚顺
538 | 新宾满族
539 | 清原满族
540 | 本溪
541 | 本溪
542 | 平山
543 | 溪湖
544 | 明山
545 | 南芬
546 | 本溪满族
547 | 桓仁满族
548 | 丹东
549 | 丹东
550 | 元宝
551 | 振兴
552 | 振安
553 | 宽甸满族
554 | 东港
555 | 凤城
556 | 锦州
557 | 锦州
558 | 古塔
559 | 凌河
560 | 太和
561 | 黑山
562 | 义
563 | 凌海
564 | 北镇
565 | 营口
566 | 营口
567 | 站前
568 | 西
569 | 鲅鱼圈
570 | 老边
571 | 盖州
572 | 大石桥
573 | 阜新
574 | 阜新
575 | 海州
576 | 新邱
577 | 太平
578 | 清河门
579 | 细河
580 | 阜新蒙古族
581 | 彰武
582 | 辽阳
583 | 辽阳
584 | 白塔
585 | 文圣
586 | 宏伟
587 | 弓长岭
588 | 太子河
589 | 辽阳
590 | 灯塔
591 | 盘锦
592 | 盘锦
593 | 双台子
594 | 兴隆台
595 | 大洼
596 | 盘山
597 | 铁岭
598 | 铁岭
599 | 银州
600 | 清河
601 | 铁岭
602 | 西丰
603 | 昌图
604 | 调兵山
605 | 开原
606 | 朝阳
607 | 朝阳
608 | 双塔
609 | 龙城
610 | 朝阳
611 | 建平
612 | 喀喇沁左翼蒙古族
613 | 北票
614 | 凌源
615 | 葫芦岛
616 | 葫芦岛
617 | 连山
618 | 龙港
619 | 南票
620 | 绥中
621 | 建昌
622 | 兴城
623 | 吉林省
624 | 长春
625 | 长春
626 | 南关
627 | 宽城
628 | 朝阳
629 | 二道
630 | 绿园
631 | 双阳
632 | 九台
633 | 农安
634 | 榆树
635 | 德惠
636 | 吉林
637 | 吉林
638 | 昌邑
639 | 龙潭
640 | 船营
641 | 丰满
642 | 永吉
643 | 蛟河
644 | 桦甸
645 | 舒兰
646 | 磐石
647 | 四平
648 | 四平
649 | 铁西
650 | 铁东
651 | 梨树
652 | 伊通满族
653 | 公主岭
654 | 双辽
655 | 辽源
656 | 辽源
657 | 龙山
658 | 西安
659 | 东丰
660 | 东辽
661 | 通化
662 | 通化
663 | 东昌
664 | 二道江
665 | 通化
666 | 辉南
667 | 柳河
668 | 梅河口
669 | 集安
670 | 白山
671 | 白山
672 | 浑江
673 | 江源
674 | 抚松
675 | 靖宇
676 | 长白朝鲜族
677 | 临江
678 | 松原
679 | 松原
680 | 宁江
681 | 前郭尔罗斯蒙古族
682 | 长岭
683 | 乾安
684 | 扶余
685 | 白城
686 | 白城
687 | 洮北
688 | 镇赉
689 | 通榆
690 | 洮南
691 | 大安
692 | 延边朝鲜族州
693 | 延吉
694 | 图们
695 | 敦化
696 | 珲春
697 | 龙井
698 | 和龙
699 | 汪清
700 | 安图
701 | 黑龙江省
702 | 哈尔滨
703 | 哈尔滨
704 | 道里
705 | 南岗
706 | 道外
707 | 平房
708 | 松北
709 | 香坊
710 | 呼兰
711 | 阿城
712 | 双城
713 | 依兰
714 | 方正
715 | 宾
716 | 巴彦
717 | 木兰
718 | 通河
719 | 延寿
720 | 尚志
721 | 五常
722 | 齐齐哈尔
723 | 齐齐哈尔
724 | 龙沙
725 | 建华
726 | 铁锋
727 | 昂昂溪
728 | 富拉尔基
729 | 碾子山
730 | 梅里斯达斡尔族
731 | 龙江
732 | 依安
733 | 泰来
734 | 甘南
735 | 富裕
736 | 克山
737 | 克东
738 | 拜泉
739 | 讷河
740 | 鸡西
741 | 鸡西
742 | 鸡冠
743 | 恒山
744 | 滴道
745 | 梨树
746 | 城子河
747 | 麻山
748 | 鸡东
749 | 虎林
750 | 密山
751 | 鹤岗
752 | 鹤岗
753 | 向阳
754 | 工农
755 | 南山
756 | 兴安
757 | 东山
758 | 兴山
759 | 萝北
760 | 绥滨
761 | 双鸭山
762 | 双鸭山
763 | 尖山
764 | 岭东
765 | 四方台
766 | 宝山
767 | 集贤
768 | 友谊
769 | 宝清
770 | 饶河
771 | 大庆
772 | 大庆
773 | 萨尔图
774 | 龙凤
775 | 让胡路
776 | 红岗
777 | 大同
778 | 肇州
779 | 肇源
780 | 林甸
781 | 杜尔伯特蒙古族
782 | 伊春
783 | 伊春
784 | 伊春
785 | 南岔
786 | 友好
787 | 西林
788 | 翠峦
789 | 新青
790 | 美溪
791 | 金山屯
792 | 五营
793 | 乌马河
794 | 汤旺河
795 | 带岭
796 | 乌伊岭
797 | 红星
798 | 上甘岭
799 | 嘉荫
800 | 铁力
801 | 佳木斯
802 | 佳木斯
803 | 向阳
804 | 前进
805 | 东风
806 | 郊
807 | 桦南
808 | 桦川
809 | 汤原
810 | 同江
811 | 富锦
812 | 抚远
813 | 七台河
814 | 七台河
815 | 新兴
816 | 桃山
817 | 茄子河
818 | 勃利
819 | 牡丹江
820 | 牡丹江
821 | 东安
822 | 阳明
823 | 爱民
824 | 西安
825 | 林口
826 | 绥芬河
827 | 海林
828 | 宁安
829 | 穆棱
830 | 东宁
831 | 黑河
832 | 黑河
833 | 爱辉
834 | 嫩江
835 | 逊克
836 | 孙吴
837 | 北安
838 | 五大连池
839 | 绥化
840 | 绥化
841 | 北林
842 | 望奎
843 | 兰西
844 | 青冈
845 | 庆安
846 | 明水
847 | 绥棱
848 | 安达
849 | 肇东
850 | 海伦
851 | 大兴安岭地
852 | 加格达奇
853 | 呼玛
854 | 塔河
855 | 漠河
856 | 上海
857 | 上海
858 | 黄浦
859 | 徐汇
860 | 长宁
861 | 静安
862 | 普陀
863 | 虹口
864 | 杨浦
865 | 闵行
866 | 宝山
867 | 嘉定
868 | 浦东新
869 | 金山
870 | 松江
871 | 青浦
872 | 奉贤
873 | 崇明
874 | 江苏省
875 | 南京
876 | 南京
877 | 玄武
878 | 秦淮
879 | 建邺
880 | 鼓楼
881 | 浦口
882 | 栖霞
883 | 雨花台
884 | 江宁
885 | 六合
886 | 溧水
887 | 高淳
888 | 无锡
889 | 无锡
890 | 锡山
891 | 惠山
892 | 滨湖
893 | 梁溪
894 | 新吴
895 | 江阴
896 | 宜兴
897 | 徐州
898 | 徐州
899 | 鼓楼
900 | 云龙
901 | 贾汪
902 | 泉山
903 | 铜山
904 | 丰
905 | 沛
906 | 睢宁
907 | 新沂
908 | 邳州
909 | 常州
910 | 常州
911 | 天宁
912 | 钟楼
913 | 新北
914 | 武进
915 | 金坛
916 | 溧阳
917 | 苏州
918 | 苏州
919 | 虎丘
920 | 吴中
921 | 相城
922 | 姑苏
923 | 吴江
924 | 苏州工业园
925 | 常熟
926 | 张家港
927 | 昆山
928 | 太仓
929 | 南通
930 | 南通
931 | 崇川
932 | 港闸
933 | 通州
934 | 海安
935 | 如东
936 | 启东
937 | 如皋
938 | 海门
939 | 连云港
940 | 连云港
941 | 连云
942 | 海州
943 | 赣榆
944 | 东海
945 | 灌云
946 | 灌南
947 | 淮安
948 | 淮安
949 | 淮安
950 | 淮阴
951 | 清江浦
952 | 洪泽
953 | 涟水
954 | 盱眙
955 | 金湖
956 | 盐城
957 | 盐城
958 | 亭湖
959 | 盐都
960 | 大丰
961 | 响水
962 | 滨海
963 | 阜宁
964 | 射阳
965 | 建湖
966 | 东台
967 | 扬州
968 | 扬州
969 | 广陵
970 | 邗江
971 | 江都
972 | 宝应
973 | 仪征
974 | 高邮
975 | 镇江
976 | 镇江
977 | 京口
978 | 润州
979 | 丹徒
980 | 丹阳
981 | 扬中
982 | 句容
983 | 泰州
984 | 泰州
985 | 海陵
986 | 高港
987 | 姜堰
988 | 兴化
989 | 靖江
990 | 泰兴
991 | 宿迁
992 | 宿迁
993 | 宿城
994 | 宿豫
995 | 沭阳
996 | 泗阳
997 | 泗洪
998 | 浙江省
999 | 杭州
1000 | 杭州
1001 | 上城
1002 | 下城
1003 | 江干
1004 | 拱墅
1005 | 西湖
1006 | 滨江
1007 | 萧山
1008 | 余杭
1009 | 富阳
1010 | 临安
1011 | 桐庐
1012 | 淳安
1013 | 建德
1014 | 宁波
1015 | 宁波
1016 | 海曙
1017 | 江北
1018 | 北仑
1019 | 镇海
1020 | 鄞州
1021 | 奉化
1022 | 象山
1023 | 宁海
1024 | 余姚
1025 | 慈溪
1026 | 温州
1027 | 温州
1028 | 鹿城
1029 | 龙湾
1030 | 瓯海
1031 | 洞头
1032 | 永嘉
1033 | 平阳
1034 | 苍南
1035 | 文成
1036 | 泰顺
1037 | 瑞安
1038 | 乐清
1039 | 嘉兴
1040 | 嘉兴
1041 | 南湖
1042 | 秀洲
1043 | 嘉善
1044 | 海盐
1045 | 海宁
1046 | 平湖
1047 | 桐乡
1048 | 湖州
1049 | 湖州
1050 | 吴兴
1051 | 南浔
1052 | 德清
1053 | 长兴
1054 | 安吉
1055 | 绍兴
1056 | 绍兴
1057 | 越城
1058 | 柯桥
1059 | 上虞
1060 | 新昌
1061 | 诸暨
1062 | 嵊州
1063 | 金华
1064 | 金华
1065 | 婺城
1066 | 金东
1067 | 武义
1068 | 浦江
1069 | 磐安
1070 | 兰溪
1071 | 义乌
1072 | 东阳
1073 | 永康
1074 | 衢州
1075 | 衢州
1076 | 柯城
1077 | 衢江
1078 | 常山
1079 | 开化
1080 | 龙游
1081 | 江山
1082 | 舟山
1083 | 舟山
1084 | 定海
1085 | 普陀
1086 | 岱山
1087 | 嵊泗
1088 | 台州
1089 | 台州
1090 | 椒江
1091 | 黄岩
1092 | 路桥
1093 | 三门
1094 | 天台
1095 | 仙居
1096 | 温岭
1097 | 临海
1098 | 玉环
1099 | 丽水
1100 | 丽水
1101 | 莲都
1102 | 青田
1103 | 缙云
1104 | 遂昌
1105 | 松阳
1106 | 云和
1107 | 庆元
1108 | 景宁畲族
1109 | 龙泉
1110 | 安徽省
1111 | 合肥
1112 | 合肥
1113 | 瑶海
1114 | 庐阳
1115 | 蜀山
1116 | 包河
1117 | 长丰
1118 | 肥东
1119 | 肥西
1120 | 庐江
1121 | 巢湖
1122 | 芜湖
1123 | 芜湖
1124 | 镜湖
1125 | 弋江
1126 | 鸠江
1127 | 三山
1128 | 芜湖
1129 | 繁昌
1130 | 南陵
1131 | 无为
1132 | 蚌埠
1133 | 蚌埠
1134 | 龙子湖
1135 | 蚌山
1136 | 禹会
1137 | 淮上
1138 | 怀远
1139 | 五河
1140 | 固镇
1141 | 淮南
1142 | 淮南
1143 | 大通
1144 | 田家庵
1145 | 谢家集
1146 | 八公山
1147 | 潘集
1148 | 凤台
1149 | 寿
1150 | 马鞍山
1151 | 马鞍山
1152 | 花山
1153 | 雨山
1154 | 博望
1155 | 当涂
1156 | 含山
1157 | 和
1158 | 淮北
1159 | 淮北
1160 | 杜集
1161 | 相山
1162 | 烈山
1163 | 濉溪
1164 | 铜陵
1165 | 铜陵
1166 | 铜官
1167 | 义安
1168 | 郊
1169 | 枞阳
1170 | 安庆
1171 | 安庆
1172 | 迎江
1173 | 大观
1174 | 宜秀
1175 | 怀宁
1176 | 潜山
1177 | 太湖
1178 | 宿松
1179 | 望江
1180 | 岳西
1181 | 桐城
1182 | 黄山
1183 | 黄山
1184 | 屯溪
1185 | 黄山
1186 | 徽州
1187 | 歙
1188 | 休宁
1189 | 黟
1190 | 祁门
1191 | 滁州
1192 | 滁州
1193 | 琅琊
1194 | 南谯
1195 | 来安
1196 | 全椒
1197 | 定远
1198 | 凤阳
1199 | 天长
1200 | 明光
1201 | 阜阳
1202 | 阜阳
1203 | 颍州
1204 | 颍东
1205 | 颍泉
1206 | 临泉
1207 | 太和
1208 | 阜南
1209 | 颍上
1210 | 界首
1211 | 宿州
1212 | 宿州
1213 | 埇桥
1214 | 砀山
1215 | 萧
1216 | 灵璧
1217 | 泗
1218 | 六安
1219 | 六安
1220 | 金安
1221 | 裕安
1222 | 叶集
1223 | 霍邱
1224 | 舒城
1225 | 金寨
1226 | 霍山
1227 | 亳州
1228 | 亳州
1229 | 谯城
1230 | 涡阳
1231 | 蒙城
1232 | 利辛
1233 | 池州
1234 | 池州
1235 | 贵池
1236 | 东至
1237 | 石台
1238 | 青阳
1239 | 宣城
1240 | 宣城
1241 | 宣州
1242 | 郎溪
1243 | 广德
1244 | 泾
1245 | 绩溪
1246 | 旌德
1247 | 宁国
1248 | 福建省
1249 | 福州
1250 | 福州
1251 | 鼓楼
1252 | 台江
1253 | 仓山
1254 | 马尾
1255 | 晋安
1256 | 长乐
1257 | 闽侯
1258 | 连江
1259 | 罗源
1260 | 闽清
1261 | 永泰
1262 | 平潭
1263 | 福清
1264 | 厦门
1265 | 厦门
1266 | 思明
1267 | 海沧
1268 | 湖里
1269 | 集美
1270 | 同安
1271 | 翔安
1272 | 莆田
1273 | 莆田
1274 | 城厢
1275 | 涵江
1276 | 荔城
1277 | 秀屿
1278 | 仙游
1279 | 三明
1280 | 三明
1281 | 梅列
1282 | 三元
1283 | 明溪
1284 | 清流
1285 | 宁化
1286 | 大田
1287 | 尤溪
1288 | 沙
1289 | 将乐
1290 | 泰宁
1291 | 建宁
1292 | 永安
1293 | 泉州
1294 | 泉州
1295 | 鲤城
1296 | 丰泽
1297 | 洛江
1298 | 泉港
1299 | 惠安
1300 | 安溪
1301 | 永春
1302 | 德化
1303 | 金门
1304 | 石狮
1305 | 晋江
1306 | 南安
1307 | 漳州
1308 | 漳州
1309 | 芗城
1310 | 龙文
1311 | 云霄
1312 | 漳浦
1313 | 诏安
1314 | 长泰
1315 | 东山
1316 | 南靖
1317 | 平和
1318 | 华安
1319 | 龙海
1320 | 南平
1321 | 南平
1322 | 延平
1323 | 建阳
1324 | 顺昌
1325 | 浦城
1326 | 光泽
1327 | 松溪
1328 | 政和
1329 | 邵武
1330 | 武夷山
1331 | 建瓯
1332 | 龙岩
1333 | 龙岩
1334 | 新罗
1335 | 永定
1336 | 长汀
1337 | 上杭
1338 | 武平
1339 | 连城
1340 | 漳平
1341 | 宁德
1342 | 宁德
1343 | 蕉城
1344 | 霞浦
1345 | 古田
1346 | 屏南
1347 | 寿宁
1348 | 周宁
1349 | 柘荣
1350 | 福安
1351 | 福鼎
1352 | 江西省
1353 | 南昌
1354 | 南昌
1355 | 东湖
1356 | 西湖
1357 | 青云谱
1358 | 湾里
1359 | 青山湖
1360 | 新建
1361 | 南昌
1362 | 安义
1363 | 进贤
1364 | 景德镇
1365 | 景德镇
1366 | 昌江
1367 | 珠山
1368 | 浮梁
1369 | 乐平
1370 | 萍乡
1371 | 萍乡
1372 | 安源
1373 | 湘东
1374 | 莲花
1375 | 上栗
1376 | 芦溪
1377 | 九江
1378 | 九江
1379 | 濂溪
1380 | 浔阳
1381 | 柴桑
1382 | 武宁
1383 | 修水
1384 | 永修
1385 | 德安
1386 | 都昌
1387 | 湖口
1388 | 彭泽
1389 | 瑞昌
1390 | 共青城
1391 | 庐山
1392 | 新余
1393 | 新余
1394 | 渝水
1395 | 分宜
1396 | 鹰潭
1397 | 鹰潭
1398 | 月湖
1399 | 余江
1400 | 贵溪
1401 | 赣州
1402 | 赣州
1403 | 章贡
1404 | 南康
1405 | 赣
1406 | 信丰
1407 | 大余
1408 | 上犹
1409 | 崇义
1410 | 安远
1411 | 龙南
1412 | 定南
1413 | 全南
1414 | 宁都
1415 | 于都
1416 | 兴国
1417 | 会昌
1418 | 寻乌
1419 | 石城
1420 | 瑞金
1421 | 吉安
1422 | 吉安
1423 | 吉州
1424 | 青原
1425 | 吉安
1426 | 吉水
1427 | 峡江
1428 | 新干
1429 | 永丰
1430 | 泰和
1431 | 遂川
1432 | 万安
1433 | 安福
1434 | 永新
1435 | 井冈山
1436 | 宜春
1437 | 宜春
1438 | 袁州
1439 | 奉新
1440 | 万载
1441 | 上高
1442 | 宜丰
1443 | 靖安
1444 | 铜鼓
1445 | 丰城
1446 | 樟树
1447 | 高安
1448 | 抚州
1449 | 抚州
1450 | 临川
1451 | 东乡
1452 | 南城
1453 | 黎川
1454 | 南丰
1455 | 崇仁
1456 | 乐安
1457 | 宜黄
1458 | 金溪
1459 | 资溪
1460 | 广昌
1461 | 上饶
1462 | 上饶
1463 | 信州
1464 | 广丰
1465 | 上饶
1466 | 玉山
1467 | 铅山
1468 | 横峰
1469 | 弋阳
1470 | 余干
1471 | 鄱阳
1472 | 万年
1473 | 婺源
1474 | 德兴
1475 | 山东省
1476 | 济南
1477 | 济南
1478 | 历下
1479 | 中
1480 | 槐荫
1481 | 天桥
1482 | 历城
1483 | 长清
1484 | 章丘
1485 | 平阴
1486 | 济阳
1487 | 商河
1488 | 青岛
1489 | 青岛
1490 | 南
1491 | 北
1492 | 黄岛
1493 | 崂山
1494 | 李沧
1495 | 城阳
1496 | 即墨
1497 | 胶州
1498 | 平度
1499 | 莱西
1500 | 淄博
1501 | 淄博
1502 | 淄川
1503 | 张店
1504 | 博山
1505 | 临淄
1506 | 周村
1507 | 桓台
1508 | 高青
1509 | 沂源
1510 | 枣庄
1511 | 枣庄
1512 | 中
1513 | 薛城
1514 | 峄城
1515 | 台儿庄
1516 | 山亭
1517 | 滕州
1518 | 东营
1519 | 东营
1520 | 东营
1521 | 河口
1522 | 垦利
1523 | 利津
1524 | 广饶
1525 | 烟台
1526 | 烟台
1527 | 芝罘
1528 | 福山
1529 | 牟平
1530 | 莱山
1531 | 长岛
1532 | 龙口
1533 | 莱阳
1534 | 莱州
1535 | 蓬莱
1536 | 招远
1537 | 栖霞
1538 | 海阳
1539 | 潍坊
1540 | 潍坊
1541 | 潍城
1542 | 寒亭
1543 | 坊子
1544 | 奎文
1545 | 临朐
1546 | 昌乐
1547 | 青州
1548 | 诸城
1549 | 寿光
1550 | 安丘
1551 | 高密
1552 | 昌邑
1553 | 济宁
1554 | 济宁
1555 | 任城
1556 | 兖州
1557 | 微山
1558 | 鱼台
1559 | 金乡
1560 | 嘉祥
1561 | 汶上
1562 | 泗水
1563 | 梁山
1564 | 曲阜
1565 | 邹城
1566 | 泰安
1567 | 泰安
1568 | 泰山
1569 | 岱岳
1570 | 宁阳
1571 | 东平
1572 | 新泰
1573 | 肥城
1574 | 威海
1575 | 威海
1576 | 环翠
1577 | 文登
1578 | 荣成
1579 | 乳山
1580 | 日照
1581 | 日照
1582 | 东港
1583 | 岚山
1584 | 五莲
1585 | 莒
1586 | 莱芜
1587 | 钢城
1588 | 临沂
1589 | 临沂
1590 | 兰山
1591 | 罗庄
1592 | 河东
1593 | 沂南
1594 | 郯城
1595 | 沂水
1596 | 兰陵
1597 | 费
1598 | 平邑
1599 | 莒南
1600 | 蒙阴
1601 | 临沭
1602 | 德州
1603 | 德州
1604 | 德城
1605 | 陵城
1606 | 宁津
1607 | 庆云
1608 | 临邑
1609 | 齐河
1610 | 平原
1611 | 夏津
1612 | 武城
1613 | 乐陵
1614 | 禹城
1615 | 聊城
1616 | 聊城
1617 | 东昌府
1618 | 阳谷
1619 | 莘
1620 | 茌平
1621 | 东阿
1622 | 冠
1623 | 高唐
1624 | 临清
1625 | 滨州
1626 | 滨州
1627 | 滨城
1628 | 沾化
1629 | 惠民
1630 | 阳信
1631 | 无棣
1632 | 博兴
1633 | 邹平
1634 | 菏泽
1635 | 菏泽
1636 | 牡丹
1637 | 定陶
1638 | 曹
1639 | 单
1640 | 成武
1641 | 巨野
1642 | 郓城
1643 | 鄄城
1644 | 东明
1645 | 河南省
1646 | 郑州
1647 | 郑州
1648 | 中原
1649 | 二七
1650 | 管城回族
1651 | 金水
1652 | 上街
1653 | 惠济
1654 | 中牟
1655 | 巩义
1656 | 荥阳
1657 | 新密
1658 | 新郑
1659 | 登封
1660 | 开封
1661 | 开封
1662 | 龙亭
1663 | 顺河回族
1664 | 鼓楼
1665 | 禹王台
1666 | 祥符
1667 | 杞
1668 | 通许
1669 | 尉氏
1670 | 兰考
1671 | 洛阳
1672 | 洛阳
1673 | 老城
1674 | 西工
1675 | 瀍河回族
1676 | 涧西
1677 | 吉利
1678 | 洛龙
1679 | 孟津
1680 | 新安
1681 | 栾川
1682 | 嵩
1683 | 汝阳
1684 | 宜阳
1685 | 洛宁
1686 | 伊川
1687 | 偃师
1688 | 平顶山
1689 | 平顶山
1690 | 新华
1691 | 卫东
1692 | 石龙
1693 | 湛河
1694 | 宝丰
1695 | 叶
1696 | 鲁山
1697 | 郏
1698 | 舞钢
1699 | 汝州
1700 | 安阳
1701 | 安阳
1702 | 文峰
1703 | 北关
1704 | 殷都
1705 | 龙安
1706 | 安阳
1707 | 汤阴
1708 | 滑
1709 | 内黄
1710 | 林州
1711 | 鹤壁
1712 | 鹤壁
1713 | 鹤山
1714 | 山城
1715 | 淇滨
1716 | 浚
1717 | 淇
1718 | 新乡
1719 | 新乡
1720 | 红旗
1721 | 卫滨
1722 | 凤泉
1723 | 牧野
1724 | 新乡
1725 | 获嘉
1726 | 原阳
1727 | 延津
1728 | 封丘
1729 | 长垣
1730 | 卫辉
1731 | 辉
1732 | 焦作
1733 | 焦作
1734 | 解放
1735 | 中站
1736 | 马村
1737 | 山阳
1738 | 修武
1739 | 博爱
1740 | 武陟
1741 | 温
1742 | 沁阳
1743 | 孟州
1744 | 濮阳
1745 | 濮阳
1746 | 华龙
1747 | 清丰
1748 | 南乐
1749 | 范
1750 | 台前
1751 | 濮阳
1752 | 许昌
1753 | 许昌
1754 | 魏都
1755 | 建安
1756 | 鄢陵
1757 | 襄城
1758 | 禹州
1759 | 长葛
1760 | 漯河
1761 | 漯河
1762 | 源汇
1763 | 郾城
1764 | 召陵
1765 | 舞阳
1766 | 临颍
1767 | 三门峡
1768 | 三门峡
1769 | 湖滨
1770 | 陕州
1771 | 渑池
1772 | 卢氏
1773 | 义马
1774 | 灵宝
1775 | 南阳
1776 | 南阳
1777 | 宛城
1778 | 卧龙
1779 | 南召
1780 | 方城
1781 | 西峡
1782 | 镇平
1783 | 内乡
1784 | 淅川
1785 | 社旗
1786 | 唐河
1787 | 新野
1788 | 桐柏
1789 | 邓州
1790 | 商丘
1791 | 商丘
1792 | 梁园
1793 | 睢阳
1794 | 民权
1795 | 睢
1796 | 宁陵
1797 | 柘城
1798 | 虞城
1799 | 夏邑
1800 | 永城
1801 | 信阳
1802 | 信阳
1803 | 浉河
1804 | 平桥
1805 | 罗山
1806 | 光山
1807 | 新
1808 | 商城
1809 | 固始
1810 | 潢川
1811 | 淮滨
1812 | 息
1813 | 周口
1814 | 周口
1815 | 川汇
1816 | 扶沟
1817 | 西华
1818 | 商水
1819 | 沈丘
1820 | 郸城
1821 | 淮阳
1822 | 太康
1823 | 鹿邑
1824 | 项城
1825 | 驻马店
1826 | 驻马店
1827 | 驿城
1828 | 西平
1829 | 上蔡
1830 | 平舆
1831 | 正阳
1832 | 确山
1833 | 泌阳
1834 | 汝南
1835 | 遂平
1836 | 新蔡
1837 | 济源
1838 | 湖北省
1839 | 武汉
1840 | 武汉
1841 | 江岸
1842 | 江汉
1843 | 硚口
1844 | 汉阳
1845 | 武昌
1846 | 青山
1847 | 洪山
1848 | 东西湖
1849 | 汉南
1850 | 蔡甸
1851 | 江夏
1852 | 黄陂
1853 | 新洲
1854 | 黄石
1855 | 黄石
1856 | 黄石港
1857 | 西塞山
1858 | 下陆
1859 | 铁山
1860 | 阳新
1861 | 大冶
1862 | 十堰
1863 | 十堰
1864 | 茅箭
1865 | 张湾
1866 | 郧阳
1867 | 郧西
1868 | 竹山
1869 | 竹溪
1870 | 房
1871 | 丹江口
1872 | 宜昌
1873 | 宜昌
1874 | 西陵
1875 | 伍家岗
1876 | 点军
1877 | 猇亭
1878 | 夷陵
1879 | 远安
1880 | 兴山
1881 | 秭归
1882 | 长阳土家族
1883 | 五峰土家族
1884 | 宜都
1885 | 当阳
1886 | 枝江
1887 | 襄阳
1888 | 襄阳
1889 | 襄城
1890 | 樊城
1891 | 襄州
1892 | 南漳
1893 | 谷城
1894 | 保康
1895 | 老河口
1896 | 枣阳
1897 | 宜城
1898 | 鄂州
1899 | 鄂州
1900 | 梁子湖
1901 | 华容
1902 | 鄂城
1903 | 荆门
1904 | 荆门
1905 | 东宝
1906 | 掇刀
1907 | 京山
1908 | 沙洋
1909 | 钟祥
1910 | 孝感
1911 | 孝感
1912 | 孝南
1913 | 孝昌
1914 | 大悟
1915 | 云梦
1916 | 应城
1917 | 安陆
1918 | 汉川
1919 | 荆州
1920 | 荆州
1921 | 沙
1922 | 荆州
1923 | 公安
1924 | 监利
1925 | 江陵
1926 | 石首
1927 | 洪湖
1928 | 松滋
1929 | 黄冈
1930 | 黄冈
1931 | 黄州
1932 | 团风
1933 | 红安
1934 | 罗田
1935 | 英山
1936 | 浠水
1937 | 蕲春
1938 | 黄梅
1939 | 麻城
1940 | 武穴
1941 | 咸宁
1942 | 咸宁
1943 | 咸安
1944 | 嘉鱼
1945 | 通城
1946 | 崇阳
1947 | 通山
1948 | 赤壁
1949 | 随州
1950 | 随州
1951 | 曾都
1952 | 随
1953 | 广水
1954 | 恩施土家族苗族州
1955 | 恩施
1956 | 利川
1957 | 建始
1958 | 巴东
1959 | 宣恩
1960 | 咸丰
1961 | 来凤
1962 | 鹤峰
1963 | 仙桃
1964 | 潜江
1965 | 天门
1966 | 神农架林
1967 | 湖南省
1968 | 长沙
1969 | 长沙
1970 | 芙蓉
1971 | 天心
1972 | 岳麓
1973 | 开福
1974 | 雨花
1975 | 望城
1976 | 长沙
1977 | 浏阳
1978 | 宁乡
1979 | 株洲
1980 | 株洲
1981 | 荷塘
1982 | 芦淞
1983 | 石峰
1984 | 天元
1985 | 渌口
1986 | 攸
1987 | 茶陵
1988 | 炎陵
1989 | 醴陵
1990 | 湘潭
1991 | 湘潭
1992 | 雨湖
1993 | 岳塘
1994 | 湘潭
1995 | 湘乡
1996 | 韶山
1997 | 衡阳
1998 | 衡阳
1999 | 珠晖
2000 | 雁峰
2001 | 石鼓
2002 | 蒸湘
2003 | 南岳
2004 | 衡阳
2005 | 衡南
2006 | 衡山
2007 | 衡东
2008 | 祁东
2009 | 耒阳
2010 | 常宁
2011 | 邵阳
2012 | 邵阳
2013 | 双清
2014 | 大祥
2015 | 北塔
2016 | 邵东
2017 | 新邵
2018 | 邵阳
2019 | 隆回
2020 | 洞口
2021 | 绥宁
2022 | 新宁
2023 | 城步苗族
2024 | 武冈
2025 | 岳阳
2026 | 岳阳
2027 | 岳阳楼
2028 | 云溪
2029 | 君山
2030 | 岳阳
2031 | 华容
2032 | 湘阴
2033 | 平江
2034 | 汨罗
2035 | 临湘
2036 | 常德
2037 | 常德
2038 | 武陵
2039 | 鼎城
2040 | 安乡
2041 | 汉寿
2042 | 澧
2043 | 临澧
2044 | 桃源
2045 | 石门
2046 | 津
2047 | 张家界
2048 | 张家界
2049 | 永定
2050 | 武陵源
2051 | 慈利
2052 | 桑植
2053 | 益阳
2054 | 益阳
2055 | 资阳
2056 | 赫山
2057 | 南
2058 | 桃江
2059 | 安化
2060 | 沅江
2061 | 郴州
2062 | 郴州
2063 | 北湖
2064 | 苏仙
2065 | 桂阳
2066 | 宜章
2067 | 永兴
2068 | 嘉禾
2069 | 临武
2070 | 汝城
2071 | 桂东
2072 | 安仁
2073 | 资兴
2074 | 永州
2075 | 永州
2076 | 零陵
2077 | 冷水滩
2078 | 祁阳
2079 | 东安
2080 | 双牌
2081 | 道
2082 | 江永
2083 | 宁远
2084 | 蓝山
2085 | 新田
2086 | 江华瑶族
2087 | 怀化
2088 | 怀化
2089 | 鹤城
2090 | 中方
2091 | 沅陵
2092 | 辰溪
2093 | 溆浦
2094 | 会同
2095 | 麻阳苗族
2096 | 新晃侗族
2097 | 芷江侗族
2098 | 靖州苗族侗族
2099 | 通道侗族
2100 | 洪江
2101 | 娄底
2102 | 娄底
2103 | 娄星
2104 | 双峰
2105 | 新化
2106 | 冷水江
2107 | 涟源
2108 | 湘西土家族苗族州
2109 | 吉首
2110 | 泸溪
2111 | 凤凰
2112 | 花垣
2113 | 保靖
2114 | 古丈
2115 | 永顺
2116 | 龙山
2117 | 广东省
2118 | 广州
2119 | 广州
2120 | 荔湾
2121 | 越秀
2122 | 海珠
2123 | 天河
2124 | 白云
2125 | 黄埔
2126 | 番禺
2127 | 花都
2128 | 南沙
2129 | 从化
2130 | 增城
2131 | 韶关
2132 | 韶关
2133 | 武江
2134 | 浈江
2135 | 曲江
2136 | 始兴
2137 | 仁化
2138 | 翁源
2139 | 乳源瑶族
2140 | 新丰
2141 | 乐昌
2142 | 南雄
2143 | 深圳
2144 | 深圳
2145 | 罗湖
2146 | 福田
2147 | 南山
2148 | 宝安
2149 | 龙岗
2150 | 盐田
2151 | 龙华
2152 | 坪山
2153 | 光明
2154 | 珠海
2155 | 珠海
2156 | 香洲
2157 | 斗门
2158 | 金湾
2159 | 汕头
2160 | 汕头
2161 | 龙湖
2162 | 金平
2163 | 濠江
2164 | 潮阳
2165 | 潮南
2166 | 澄海
2167 | 南澳
2168 | 佛山
2169 | 佛山
2170 | 禅城
2171 | 南海
2172 | 顺德
2173 | 三水
2174 | 高明
2175 | 江门
2176 | 江门
2177 | 蓬江
2178 | 江海
2179 | 新会
2180 | 台山
2181 | 开平
2182 | 鹤山
2183 | 恩平
2184 | 湛江
2185 | 湛江
2186 | 赤坎
2187 | 霞山
2188 | 坡头
2189 | 麻章
2190 | 遂溪
2191 | 徐闻
2192 | 廉江
2193 | 雷州
2194 | 吴川
2195 | 茂名
2196 | 茂名
2197 | 茂南
2198 | 电白
2199 | 高州
2200 | 化州
2201 | 信宜
2202 | 肇庆
2203 | 肇庆
2204 | 端州
2205 | 鼎湖
2206 | 高要
2207 | 广宁
2208 | 怀集
2209 | 封开
2210 | 德庆
2211 | 四会
2212 | 惠州
2213 | 惠州
2214 | 惠城
2215 | 惠阳
2216 | 博罗
2217 | 惠东
2218 | 龙门
2219 | 梅州
2220 | 梅州
2221 | 梅江
2222 | 梅
2223 | 大埔
2224 | 丰顺
2225 | 五华
2226 | 平远
2227 | 蕉岭
2228 | 兴宁
2229 | 汕尾
2230 | 汕尾
2231 | 城
2232 | 海丰
2233 | 陆河
2234 | 陆丰
2235 | 河源
2236 | 河源
2237 | 源城
2238 | 紫金
2239 | 龙川
2240 | 连平
2241 | 和平
2242 | 东源
2243 | 阳江
2244 | 阳江
2245 | 江城
2246 | 阳东
2247 | 阳西
2248 | 阳春
2249 | 清远
2250 | 清远
2251 | 清城
2252 | 清新
2253 | 佛冈
2254 | 阳山
2255 | 连山壮族瑶族
2256 | 连南瑶族
2257 | 英德
2258 | 连州
2259 | 东莞
2260 | 中山
2261 | 东沙群岛
2262 | 潮州
2263 | 潮州
2264 | 湘桥
2265 | 潮安
2266 | 饶平
2267 | 揭阳
2268 | 揭阳
2269 | 榕城
2270 | 揭东
2271 | 揭西
2272 | 惠来
2273 | 普宁
2274 | 云浮
2275 | 云浮
2276 | 云城
2277 | 云安
2278 | 新兴
2279 | 郁南
2280 | 罗定
2281 | 广西壮族
2282 | 南宁
2283 | 南宁
2284 | 兴宁
2285 | 青秀
2286 | 江南
2287 | 西乡塘
2288 | 良庆
2289 | 邕宁
2290 | 武鸣
2291 | 隆安
2292 | 马山
2293 | 上林
2294 | 宾阳
2295 | 横
2296 | 柳州
2297 | 柳州
2298 | 城中
2299 | 鱼峰
2300 | 柳南
2301 | 柳北
2302 | 柳江
2303 | 柳城
2304 | 鹿寨
2305 | 融安
2306 | 融水苗族
2307 | 三江侗族
2308 | 桂林
2309 | 桂林
2310 | 秀峰
2311 | 叠彩
2312 | 象山
2313 | 七星
2314 | 雁山
2315 | 临桂
2316 | 阳朔
2317 | 灵川
2318 | 全州
2319 | 兴安
2320 | 永福
2321 | 灌阳
2322 | 龙胜各族
2323 | 资源
2324 | 平乐
2325 | 荔浦
2326 | 恭城瑶族
2327 | 梧州
2328 | 梧州
2329 | 万秀
2330 | 长洲
2331 | 龙圩
2332 | 苍梧
2333 | 藤
2334 | 蒙山
2335 | 岑溪
2336 | 北海
2337 | 北海
2338 | 海城
2339 | 银海
2340 | 铁山港
2341 | 合浦
2342 | 防城港
2343 | 防城港
2344 | 港口
2345 | 防城
2346 | 上思
2347 | 东兴
2348 | 钦州
2349 | 钦州
2350 | 钦南
2351 | 钦北
2352 | 灵山
2353 | 浦北
2354 | 贵港
2355 | 贵港
2356 | 港北
2357 | 港南
2358 | 覃塘
2359 | 平南
2360 | 桂平
2361 | 玉林
2362 | 玉林
2363 | 玉州
2364 | 福绵
2365 | 容
2366 | 陆川
2367 | 博白
2368 | 兴业
2369 | 北流
2370 | 百色
2371 | 百色
2372 | 右江
2373 | 田阳
2374 | 田东
2375 | 平果
2376 | 德保
2377 | 那坡
2378 | 凌云
2379 | 乐业
2380 | 田林
2381 | 西林
2382 | 隆林各族
2383 | 靖西
2384 | 贺州
2385 | 贺州
2386 | 八步
2387 | 平桂
2388 | 昭平
2389 | 钟山
2390 | 富川瑶族
2391 | 河池
2392 | 河池
2393 | 金城江
2394 | 宜州
2395 | 南丹
2396 | 天峨
2397 | 凤山
2398 | 东兰
2399 | 罗城仫佬族
2400 | 环江毛南族
2401 | 巴马瑶族
2402 | 都安瑶族
2403 | 大化瑶族
2404 | 来宾
2405 | 来宾
2406 | 兴宾
2407 | 忻城
2408 | 象州
2409 | 武宣
2410 | 金秀瑶族
2411 | 合山
2412 | 崇左
2413 | 崇左
2414 | 江州
2415 | 扶绥
2416 | 宁明
2417 | 龙州
2418 | 大新
2419 | 天等
2420 | 凭祥
2421 | 海南省
2422 | 海口
2423 | 海口
2424 | 秀英
2425 | 龙华
2426 | 琼山
2427 | 美兰
2428 | 三亚
2429 | 三亚
2430 | 海棠
2431 | 吉阳
2432 | 天涯
2433 | 崖州
2434 | 三沙
2435 | 三沙
2436 | 西沙群岛
2437 | 南沙群岛
2438 | 中沙群岛的岛礁及其海域
2439 | 儋州
2440 | 五指山
2441 | 琼海
2442 | 文昌
2443 | 万宁
2444 | 东方
2445 | 定安
2446 | 屯昌
2447 | 澄迈
2448 | 临高
2449 | 白沙黎族
2450 | 昌江黎族
2451 | 乐东黎族
2452 | 陵水黎族
2453 | 保亭黎族苗族
2454 | 琼中黎族苗族
2455 | 重庆
2456 | 重庆
2457 | 万州
2458 | 涪陵
2459 | 渝中
2460 | 大渡口
2461 | 江北
2462 | 沙坪坝
2463 | 九龙坡
2464 | 南岸
2465 | 北碚
2466 | 綦江
2467 | 大足
2468 | 渝北
2469 | 巴南
2470 | 黔江
2471 | 长寿
2472 | 江津
2473 | 合川
2474 | 永川
2475 | 南川
2476 | 璧山
2477 | 铜梁
2478 | 潼南
2479 | 荣昌
2480 | 开州
2481 | 梁平
2482 | 武隆
2483 | 重庆郊
2484 | 城口
2485 | 丰都
2486 | 垫江
2487 | 忠
2488 | 云阳
2489 | 奉节
2490 | 巫山
2491 | 巫溪
2492 | 石柱土家族
2493 | 秀山土家族苗族
2494 | 酉阳土家族苗族
2495 | 彭水苗族土家族
2496 | 四川省
2497 | 成都
2498 | 成都
2499 | 锦江
2500 | 青羊
2501 | 金牛
2502 | 武侯
2503 | 成华
2504 | 龙泉驿
2505 | 青白江
2506 | 新都
2507 | 温江
2508 | 双流
2509 | 郫都
2510 | 金堂
2511 | 大邑
2512 | 蒲江
2513 | 新津
2514 | 都江堰
2515 | 彭州
2516 | 邛崃
2517 | 崇州
2518 | 简阳
2519 | 自贡
2520 | 自贡
2521 | 自流井
2522 | 贡井
2523 | 大安
2524 | 沿滩
2525 | 荣
2526 | 富顺
2527 | 攀枝花
2528 | 攀枝花
2529 | 东
2530 | 西
2531 | 仁和
2532 | 米易
2533 | 盐边
2534 | 泸州
2535 | 泸州
2536 | 江阳
2537 | 纳溪
2538 | 龙马潭
2539 | 泸
2540 | 合江
2541 | 叙永
2542 | 古蔺
2543 | 德阳
2544 | 德阳
2545 | 旌阳
2546 | 中江
2547 | 罗江
2548 | 广汉
2549 | 什邡
2550 | 绵竹
2551 | 绵阳
2552 | 绵阳
2553 | 涪城
2554 | 游仙
2555 | 安州
2556 | 三台
2557 | 盐亭
2558 | 梓潼
2559 | 北川羌族
2560 | 平武
2561 | 江油
2562 | 广元
2563 | 广元
2564 | 利州
2565 | 昭化
2566 | 朝天
2567 | 旺苍
2568 | 青川
2569 | 剑阁
2570 | 苍溪
2571 | 遂宁
2572 | 遂宁
2573 | 船山
2574 | 安居
2575 | 蓬溪
2576 | 射洪
2577 | 大英
2578 | 内江
2579 | 内江
2580 | 中
2581 | 东兴
2582 | 威远
2583 | 资中
2584 | 隆昌
2585 | 乐山
2586 | 乐山
2587 | 中
2588 | 沙湾
2589 | 五通桥
2590 | 金口河
2591 | 犍为
2592 | 井研
2593 | 夹江
2594 | 沐川
2595 | 峨边彝族
2596 | 马边彝族
2597 | 峨眉山
2598 | 南充
2599 | 南充
2600 | 顺庆
2601 | 高坪
2602 | 嘉陵
2603 | 南部
2604 | 营山
2605 | 蓬安
2606 | 仪陇
2607 | 西充
2608 | 阆中
2609 | 眉山
2610 | 眉山
2611 | 东坡
2612 | 彭山
2613 | 仁寿
2614 | 洪雅
2615 | 丹棱
2616 | 青神
2617 | 宜宾
2618 | 宜宾
2619 | 翠屏
2620 | 南溪
2621 | 叙州
2622 | 江安
2623 | 长宁
2624 | 高
2625 | 珙
2626 | 筠连
2627 | 兴文
2628 | 屏山
2629 | 广安
2630 | 广安
2631 | 广安
2632 | 前锋
2633 | 岳池
2634 | 武胜
2635 | 邻水
2636 | 华蓥
2637 | 达州
2638 | 达州
2639 | 通川
2640 | 达川
2641 | 宣汉
2642 | 开江
2643 | 大竹
2644 | 渠
2645 | 万源
2646 | 雅安
2647 | 雅安
2648 | 雨城
2649 | 名山
2650 | 荥经
2651 | 汉源
2652 | 石棉
2653 | 天全
2654 | 芦山
2655 | 宝兴
2656 | 巴中
2657 | 巴中
2658 | 巴州
2659 | 恩阳
2660 | 通江
2661 | 南江
2662 | 平昌
2663 | 资阳
2664 | 资阳
2665 | 雁江
2666 | 安岳
2667 | 乐至
2668 | 阿坝藏族羌族州
2669 | 马尔康
2670 | 汶川
2671 | 理
2672 | 茂
2673 | 松潘
2674 | 九寨沟
2675 | 金川
2676 | 小金
2677 | 黑水
2678 | 壤塘
2679 | 阿坝
2680 | 若尔盖
2681 | 红原
2682 | 甘孜藏族州
2683 | 康定
2684 | 泸定
2685 | 丹巴
2686 | 九龙
2687 | 雅江
2688 | 道孚
2689 | 炉霍
2690 | 甘孜
2691 | 新龙
2692 | 德格
2693 | 白玉
2694 | 石渠
2695 | 色达
2696 | 理塘
2697 | 巴塘
2698 | 乡城
2699 | 稻城
2700 | 得荣
2701 | 凉山彝族州
2702 | 西昌
2703 | 木里藏族
2704 | 盐源
2705 | 德昌
2706 | 会理
2707 | 会东
2708 | 宁南
2709 | 普格
2710 | 布拖
2711 | 金阳
2712 | 昭觉
2713 | 喜德
2714 | 冕宁
2715 | 越西
2716 | 甘洛
2717 | 美姑
2718 | 雷波
2719 | 贵州省
2720 | 贵阳
2721 | 贵阳
2722 | 南明
2723 | 云岩
2724 | 花溪
2725 | 乌当
2726 | 白云
2727 | 观山湖
2728 | 开阳
2729 | 息烽
2730 | 修文
2731 | 清镇
2732 | 六盘水
2733 | 钟山
2734 | 六枝特
2735 | 水城
2736 | 盘州
2737 | 遵义
2738 | 遵义
2739 | 红花岗
2740 | 汇川
2741 | 播州
2742 | 桐梓
2743 | 绥阳
2744 | 正安
2745 | 道真仡佬族苗族
2746 | 务川仡佬族苗族
2747 | 凤冈
2748 | 湄潭
2749 | 余庆
2750 | 习水
2751 | 赤水
2752 | 仁怀
2753 | 安顺
2754 | 安顺
2755 | 西秀
2756 | 平坝
2757 | 普定
2758 | 镇宁布依族苗族
2759 | 关岭布依族苗族
2760 | 紫云苗族布依族
2761 | 毕节
2762 | 七星关
2763 | 大方
2764 | 黔西
2765 | 金沙
2766 | 织金
2767 | 纳雍
2768 | 威宁彝族回族苗族
2769 | 赫章
2770 | 铜仁
2771 | 碧江
2772 | 万山
2773 | 江口
2774 | 玉屏侗族
2775 | 石阡
2776 | 思南
2777 | 印江土家族苗族
2778 | 德江
2779 | 沿河土家族
2780 | 松桃苗族
2781 | 黔西南布依族苗族州
2782 | 兴义
2783 | 兴仁
2784 | 普安
2785 | 晴隆
2786 | 贞丰
2787 | 望谟
2788 | 册亨
2789 | 安龙
2790 | 黔东南苗族侗族州
2791 | 凯里
2792 | 黄平
2793 | 施秉
2794 | 三穗
2795 | 镇远
2796 | 岑巩
2797 | 天柱
2798 | 锦屏
2799 | 剑河
2800 | 台江
2801 | 黎平
2802 | 榕江
2803 | 从江
2804 | 雷山
2805 | 麻江
2806 | 丹寨
2807 | 黔南布依族苗族州
2808 | 都匀
2809 | 福泉
2810 | 荔波
2811 | 贵定
2812 | 瓮安
2813 | 独山
2814 | 平塘
2815 | 罗甸
2816 | 长顺
2817 | 龙里
2818 | 惠水
2819 | 三都水族
2820 | 云南省
2821 | 昆明
2822 | 昆明
2823 | 五华
2824 | 盘龙
2825 | 官渡
2826 | 西山
2827 | 东川
2828 | 呈贡
2829 | 晋宁
2830 | 富民
2831 | 宜良
2832 | 石林彝族
2833 | 嵩明
2834 | 禄劝彝族苗族
2835 | 寻甸回族彝族
2836 | 安宁
2837 | 曲靖
2838 | 曲靖
2839 | 麒麟
2840 | 沾益
2841 | 马龙
2842 | 陆良
2843 | 师宗
2844 | 罗平
2845 | 富源
2846 | 会泽
2847 | 宣威
2848 | 玉溪
2849 | 玉溪
2850 | 红塔
2851 | 江川
2852 | 澄江
2853 | 通海
2854 | 华宁
2855 | 易门
2856 | 峨山彝族
2857 | 新平彝族傣族
2858 | 元江哈尼族彝族傣族
2859 | 保山
2860 | 保山
2861 | 隆阳
2862 | 施甸
2863 | 龙陵
2864 | 昌宁
2865 | 腾冲
2866 | 昭通
2867 | 昭通
2868 | 昭阳
2869 | 鲁甸
2870 | 巧家
2871 | 盐津
2872 | 大关
2873 | 永善
2874 | 绥江
2875 | 镇雄
2876 | 彝良
2877 | 威信
2878 | 水富
2879 | 丽江
2880 | 丽江
2881 | 古城
2882 | 玉龙纳西族
2883 | 永胜
2884 | 华坪
2885 | 宁蒗彝族
2886 | 普洱
2887 | 普洱
2888 | 思茅
2889 | 宁洱哈尼族彝族
2890 | 墨江哈尼族
2891 | 景东彝族
2892 | 景谷傣族彝族
2893 | 镇沅彝族哈尼族拉祜族
2894 | 江城哈尼族彝族
2895 | 孟连傣族拉祜族佤族
2896 | 澜沧拉祜族
2897 | 西盟佤族
2898 | 临沧
2899 | 临沧
2900 | 临翔
2901 | 凤庆
2902 | 云
2903 | 永德
2904 | 镇康
2905 | 双江拉祜族佤族布朗族傣族
2906 | 耿马傣族佤族
2907 | 沧源佤族
2908 | 楚雄彝族州
2909 | 楚雄
2910 | 双柏
2911 | 牟定
2912 | 南华
2913 | 姚安
2914 | 大姚
2915 | 永仁
2916 | 元谋
2917 | 武定
2918 | 禄丰
2919 | 红河哈尼族彝族州
2920 | 个旧
2921 | 开远
2922 | 蒙自
2923 | 弥勒
2924 | 屏边苗族
2925 | 建水
2926 | 石屏
2927 | 泸西
2928 | 元阳
2929 | 红河
2930 | 金平苗族瑶族傣族
2931 | 绿春
2932 | 河口瑶族
2933 | 文山壮族苗族州
2934 | 文山
2935 | 砚山
2936 | 西畴
2937 | 麻栗坡
2938 | 马关
2939 | 丘北
2940 | 广南
2941 | 富宁
2942 | 西双版纳傣族州
2943 | 景洪
2944 | 勐海
2945 | 勐腊
2946 | 大理白族州
2947 | 大理
2948 | 漾濞彝族
2949 | 祥云
2950 | 宾川
2951 | 弥渡
2952 | 南涧彝族
2953 | 巍山彝族回族
2954 | 永平
2955 | 云龙
2956 | 洱源
2957 | 剑川
2958 | 鹤庆
2959 | 德宏傣族景颇族州
2960 | 瑞丽
2961 | 芒
2962 | 梁河
2963 | 盈江
2964 | 陇川
2965 | 怒江傈僳族州
2966 | 泸水
2967 | 福贡
2968 | 贡山独龙族怒族
2969 | 兰坪白族普米族
2970 | 迪庆藏族州
2971 | 香格里拉
2972 | 德钦
2973 | 维西傈僳族
2974 | 西藏
2975 | 拉萨
2976 | 拉萨
2977 | 城关
2978 | 堆龙德庆
2979 | 达孜
2980 | 林周
2981 | 当雄
2982 | 尼木
2983 | 曲水
2984 | 墨竹工卡
2985 | 日喀则
2986 | 桑珠孜
2987 | 南木林
2988 | 江孜
2989 | 定日
2990 | 萨迦
2991 | 拉孜
2992 | 昂仁
2993 | 谢通门
2994 | 白朗
2995 | 仁布
2996 | 康马
2997 | 定结
2998 | 仲巴
2999 | 亚东
3000 | 吉隆
3001 | 聂拉木
3002 | 萨嘎
3003 | 岗巴
3004 | 昌都
3005 | 卡若
3006 | 江达
3007 | 贡觉
3008 | 类乌齐
3009 | 丁青
3010 | 察雅
3011 | 八宿
3012 | 左贡
3013 | 芒康
3014 | 洛隆
3015 | 边坝
3016 | 林芝
3017 | 巴宜
3018 | 工布江达
3019 | 米林
3020 | 墨脱
3021 | 波密
3022 | 察隅
3023 | 朗
3024 | 山南
3025 | 乃东
3026 | 扎囊
3027 | 贡嘎
3028 | 桑日
3029 | 琼结
3030 | 曲松
3031 | 措美
3032 | 洛扎
3033 | 加查
3034 | 隆子
3035 | 错那
3036 | 浪卡子
3037 | 那曲
3038 | 色尼
3039 | 嘉黎
3040 | 比如
3041 | 聂荣
3042 | 安多
3043 | 申扎
3044 | 索
3045 | 班戈
3046 | 巴青
3047 | 尼玛
3048 | 双湖
3049 | 阿里地
3050 | 普兰
3051 | 札达
3052 | 噶尔
3053 | 日土
3054 | 革吉
3055 | 改则
3056 | 措勤
3057 | 陕西省
3058 | 西安
3059 | 西安
3060 | 新城
3061 | 碑林
3062 | 莲湖
3063 | 灞桥
3064 | 未央
3065 | 雁塔
3066 | 阎良
3067 | 临潼
3068 | 长安
3069 | 高陵
3070 | 鄠邑
3071 | 蓝田
3072 | 周至
3073 | 铜川
3074 | 铜川
3075 | 王益
3076 | 印台
3077 | 耀州
3078 | 宜君
3079 | 宝鸡
3080 | 宝鸡
3081 | 渭滨
3082 | 金台
3083 | 陈仓
3084 | 凤翔
3085 | 岐山
3086 | 扶风
3087 | 眉
3088 | 陇
3089 | 千阳
3090 | 麟游
3091 | 凤
3092 | 太白
3093 | 咸阳
3094 | 咸阳
3095 | 秦都
3096 | 杨陵
3097 | 渭城
3098 | 三原
3099 | 泾阳
3100 | 乾
3101 | 礼泉
3102 | 永寿
3103 | 彬州
3104 | 长武
3105 | 旬邑
3106 | 淳化
3107 | 武功
3108 | 兴平
3109 | 渭南
3110 | 渭南
3111 | 临渭
3112 | 华州
3113 | 潼关
3114 | 大荔
3115 | 合阳
3116 | 澄城
3117 | 蒲城
3118 | 白水
3119 | 富平
3120 | 韩城
3121 | 华阴
3122 | 延安
3123 | 延安
3124 | 宝塔
3125 | 安塞
3126 | 延长
3127 | 延川
3128 | 子长
3129 | 志丹
3130 | 吴起
3131 | 甘泉
3132 | 富
3133 | 洛川
3134 | 宜川
3135 | 黄龙
3136 | 黄陵
3137 | 汉中
3138 | 汉中
3139 | 汉台
3140 | 南郑
3141 | 城固
3142 | 洋
3143 | 西乡
3144 | 勉
3145 | 宁强
3146 | 略阳
3147 | 镇巴
3148 | 留坝
3149 | 佛坪
3150 | 榆林
3151 | 榆林
3152 | 榆阳
3153 | 横山
3154 | 府谷
3155 | 靖边
3156 | 定边
3157 | 绥德
3158 | 米脂
3159 | 佳
3160 | 吴堡
3161 | 清涧
3162 | 子洲
3163 | 神木
3164 | 安康
3165 | 安康
3166 | 汉滨
3167 | 汉阴
3168 | 石泉
3169 | 宁陕
3170 | 紫阳
3171 | 岚皋
3172 | 平利
3173 | 镇坪
3174 | 旬阳
3175 | 白河
3176 | 商洛
3177 | 商洛
3178 | 商州
3179 | 洛南
3180 | 丹凤
3181 | 商南
3182 | 山阳
3183 | 镇安
3184 | 柞水
3185 | 甘肃省
3186 | 兰州
3187 | 兰州
3188 | 城关
3189 | 七里河
3190 | 西固
3191 | 安宁
3192 | 红古
3193 | 永登
3194 | 皋兰
3195 | 榆中
3196 | 嘉峪关
3197 | 嘉峪关
3198 | 金昌
3199 | 金昌
3200 | 金川
3201 | 永昌
3202 | 白银
3203 | 白银
3204 | 白银
3205 | 平川
3206 | 靖远
3207 | 会宁
3208 | 景泰
3209 | 天水
3210 | 天水
3211 | 秦州
3212 | 麦积
3213 | 清水
3214 | 秦安
3215 | 甘谷
3216 | 武山
3217 | 张家川回族
3218 | 武威
3219 | 武威
3220 | 凉州
3221 | 民勤
3222 | 古浪
3223 | 天祝藏族
3224 | 张掖
3225 | 张掖
3226 | 甘州
3227 | 肃南裕固族
3228 | 民乐
3229 | 临泽
3230 | 高台
3231 | 山丹
3232 | 平凉
3233 | 平凉
3234 | 崆峒
3235 | 泾川
3236 | 灵台
3237 | 崇信
3238 | 华亭
3239 | 庄浪
3240 | 静宁
3241 | 酒泉
3242 | 酒泉
3243 | 肃州
3244 | 金塔
3245 | 瓜州
3246 | 肃北蒙古族
3247 | 阿克塞哈萨克族
3248 | 玉门
3249 | 敦煌
3250 | 庆阳
3251 | 庆阳
3252 | 西峰
3253 | 庆城
3254 | 环
3255 | 华池
3256 | 合水
3257 | 正宁
3258 | 宁
3259 | 镇原
3260 | 定西
3261 | 定西
3262 | 安定
3263 | 通渭
3264 | 陇西
3265 | 渭源
3266 | 临洮
3267 | 漳
3268 | 岷
3269 | 陇南
3270 | 陇南
3271 | 武都
3272 | 成
3273 | 文
3274 | 宕昌
3275 | 康
3276 | 西和
3277 | 礼
3278 | 徽
3279 | 两当
3280 | 临夏回族州
3281 | 临夏
3282 | 临夏
3283 | 康乐
3284 | 永靖
3285 | 广河
3286 | 和政
3287 | 东乡族
3288 | 积石山保安族东乡族撒拉族
3289 | 甘南藏族州
3290 | 合作
3291 | 临潭
3292 | 卓尼
3293 | 舟曲
3294 | 迭部
3295 | 玛曲
3296 | 碌曲
3297 | 夏河
3298 | 青海省
3299 | 西宁
3300 | 西宁
3301 | 城东
3302 | 城中
3303 | 城西
3304 | 城北
3305 | 大通回族土族
3306 | 湟中
3307 | 湟源
3308 | 海东
3309 | 乐都
3310 | 平安
3311 | 民和回族土族
3312 | 互助土族
3313 | 化隆回族
3314 | 循化撒拉族
3315 | 海北藏族州
3316 | 门源回族
3317 | 祁连
3318 | 海晏
3319 | 刚察
3320 | 黄南藏族州
3321 | 同仁
3322 | 尖扎
3323 | 泽库
3324 | 河南蒙古族
3325 | 海南藏族州
3326 | 共和
3327 | 同德
3328 | 贵德
3329 | 兴海
3330 | 贵南
3331 | 果洛藏族州
3332 | 玛沁
3333 | 班玛
3334 | 甘德
3335 | 达日
3336 | 久治
3337 | 玛多
3338 | 玉树藏族州
3339 | 玉树
3340 | 杂多
3341 | 称多
3342 | 治多
3343 | 囊谦
3344 | 曲麻莱
3345 | 海西蒙古族藏族州
3346 | 格尔木
3347 | 德令哈
3348 | 茫崖
3349 | 乌兰
3350 | 都兰
3351 | 天峻
3352 | 海西蒙古族藏族州直
3353 | 宁夏回族
3354 | 银川
3355 | 银川
3356 | 兴庆
3357 | 西夏
3358 | 金凤
3359 | 永宁
3360 | 贺兰
3361 | 灵武
3362 | 石嘴山
3363 | 石嘴山
3364 | 大武口
3365 | 惠农
3366 | 平罗
3367 | 吴忠
3368 | 吴忠
3369 | 利通
3370 | 红寺堡
3371 | 盐池
3372 | 同心
3373 | 青铜峡
3374 | 固原
3375 | 固原
3376 | 原州
3377 | 西吉
3378 | 隆德
3379 | 泾源
3380 | 彭阳
3381 | 中卫
3382 | 中卫
3383 | 沙坡头
3384 | 中宁
3385 | 海原
3386 | 新疆维吾尔
3387 | 乌鲁木齐
3388 | 乌鲁木齐
3389 | 天山
3390 | 沙依巴克
3391 | 新
3392 | 水磨沟
3393 | 头屯河
3394 | 达坂城
3395 | 米东
3396 | 乌鲁木齐
3397 | 克拉玛依
3398 | 克拉玛依
3399 | 独山子
3400 | 克拉玛依
3401 | 白碱滩
3402 | 乌尔禾
3403 | 吐鲁番
3404 | 高昌
3405 | 鄯善
3406 | 托克逊
3407 | 哈密
3408 | 伊州
3409 | 巴里坤哈萨克
3410 | 伊吾
3411 | 昌吉回族州
3412 | 昌吉
3413 | 阜康
3414 | 呼图壁
3415 | 玛纳斯
3416 | 奇台
3417 | 吉木萨尔
3418 | 木垒哈萨克
3419 | 博尔塔拉蒙古州
3420 | 博乐
3421 | 阿拉山口
3422 | 精河
3423 | 温泉
3424 | 巴音郭楞蒙古州
3425 | 库尔勒
3426 | 轮台
3427 | 尉犁
3428 | 若羌
3429 | 且末
3430 | 焉耆回族
3431 | 和静
3432 | 和硕
3433 | 博湖
3434 | 阿克苏地
3435 | 阿克苏
3436 | 温宿
3437 | 库车
3438 | 沙雅
3439 | 新和
3440 | 拜城
3441 | 乌什
3442 | 阿瓦提
3443 | 柯坪
3444 | 克孜勒苏柯尔克孜州
3445 | 阿图什
3446 | 阿克陶
3447 | 阿合奇
3448 | 乌恰
3449 | 喀什地
3450 | 喀什
3451 | 疏附
3452 | 疏勒
3453 | 英吉沙
3454 | 泽普
3455 | 莎车
3456 | 叶城
3457 | 麦盖提
3458 | 岳普湖
3459 | 伽师
3460 | 巴楚
3461 | 塔什库尔干塔吉克
3462 | 和田地
3463 | 和田
3464 | 和田
3465 | 墨玉
3466 | 皮山
3467 | 洛浦
3468 | 策勒
3469 | 于田
3470 | 民丰
3471 | 伊犁哈萨克州
3472 | 伊宁
3473 | 奎屯
3474 | 霍尔果斯
3475 | 伊宁
3476 | 察布查尔锡伯
3477 | 霍城
3478 | 巩留
3479 | 新源
3480 | 昭苏
3481 | 特克斯
3482 | 尼勒克
3483 | 塔城地
3484 | 塔城
3485 | 乌苏
3486 | 额敏
3487 | 沙湾
3488 | 托里
3489 | 裕民
3490 | 和布克赛尔蒙古
3491 | 阿勒泰地
3492 | 阿勒泰
3493 | 布尔津
3494 | 富蕴
3495 | 福海
3496 | 哈巴河
3497 | 青河
3498 | 吉木乃
3499 | 石河子
3500 | 阿拉尔
3501 | 图木舒克
3502 | 五家渠
3503 | 北屯
3504 | 铁门关
3505 | 双河
3506 | 可克达拉
3507 | 昆玉
3508 | 台湾
3509 | 香港
3510 | 中西
3511 | 湾仔
3512 | 东
3513 | 南
3514 | 油尖旺
3515 | 深水埗
3516 | 九龙城
3517 | 黄大仙
3518 | 观塘
3519 | 荃湾
3520 | 屯门
3521 | 元朗
3522 | 北
3523 | 大埔
3524 | 西贡
3525 | 沙田
3526 | 葵青
3527 | 离岛
3528 | 澳门
3529 | 花地玛堂
3530 | 花王堂
3531 | 望德堂
3532 | 大堂
3533 | 风顺堂
3534 | 嘉模堂
3535 | 路凼填海
3536 | 圣方济各堂
3537 |
--------------------------------------------------------------------------------
/plugins/weather/data_source_amap.py:
--------------------------------------------------------------------------------
1 | # weather info source: amap
2 | # tutorial: https://lbs.amap.com/api/webservice/guide/api/weatherinfo/
3 | # sample json fetch:
4 | # http://restapi.amap.com/v3/weather/weatherInfo?key=AAAAAAAAAAAAA&city=%E6%BE%B3%E9%97%A8&extensions=all
5 |
6 | import json
7 | import re
8 |
9 | import aiohttp
10 | from nonebot import get_bot
11 |
12 | from utils_bot.logging import logger
13 | from utils_bot.typing import Union
14 |
15 | URL_BASE: str = 'http://restapi.amap.com/v3/weather/weatherInfo?key='
16 | # +
17 | API_KEY: str = get_bot().config.AMAP_WEATHER_API_KEY
18 | # +
19 | URL_MODE: str = '&extensions=all&city='
20 | # +
21 | # city
22 |
23 | # fetch weather json data
24 | async def fetch(city: str) -> Union[dict, None]:
25 | headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'}
26 | async with aiohttp.ClientSession() as session:
27 | try:
28 | async with session.get(
29 | f'{URL_BASE}{API_KEY}{URL_MODE}{city}',
30 | headers=headers, timeout=10, ssl=False) as r:
31 | res = json.loads(await r.text(), encoding='utf-8')
32 | assert res['info'].lower() == 'ok'
33 | return res
34 | except Exception as e:
35 | logger.exception(e)
36 | return None
37 |
38 | # yields weather data
39 | def process_weatherdata(resJson: Union[dict, None]) -> str:
40 | if resJson is None:
41 | return '天气服务不可用'
42 |
43 | if not resJson['forecasts']:
44 | return '也许地址有误?'
45 | # location data
46 | province = resJson['forecasts'][0]['province']
47 | city = resJson['forecasts'][0]['city']
48 | time = resJson['forecasts'][0]['reporttime']
49 |
50 | heading = f'预报时间:{time}\n地区:{province} {city}\n'
51 | def process_wind_str(wind: str) -> str:
52 | # possible wind input: '东北', '无风'
53 | return wind + '风' if re.search(r'东|南|西|北', wind) else wind
54 | def resGen():
55 | try:
56 | for j in range(3):
57 | locCurrDay = resJson['forecasts'][0]['casts'][j]
58 | yield \
59 | f'''{locCurrDay['date']} 日:{locCurrDay['daytemp']}°C,{locCurrDay['dayweather']},{process_wind_str(locCurrDay['daywind'])}
60 | {locCurrDay['date']} 夜:{locCurrDay['nighttemp']}°C,{locCurrDay['nightweather']},{process_wind_str(locCurrDay['nightwind'])}'''
61 | except (IndexError, KeyError):
62 | pass
63 | return heading + '\n'.join(resGen())
64 |
65 | async def amap_weather(city: str):
66 | return process_weatherdata(await fetch(city))
67 |
--------------------------------------------------------------------------------
/plugins/weather/data_source_openweather.py:
--------------------------------------------------------------------------------
1 | # weather info source: openweathermap
2 | # tutorial: https://openweathermap.org/forecast5
3 | # sample json fetch:
4 | # http://api.openweathermap.org/data/2.5/forecast?appid=AAAAAAAAAAAAAAA&q=London&units=metric
5 |
6 | import json
7 | import random
8 |
9 | import aiohttp
10 | from nonebot import get_bot
11 |
12 | from utils_bot.datetime import datetime, timedelta
13 | from utils_bot.logging import logger
14 | from utils_bot.typing import Union
15 |
16 | # 'weather' for current weather instead
17 | URL_BASE: str = 'http://api.openweathermap.org/data/2.5/forecast?appid='
18 | # +
19 | API_KEY: str = get_bot().config.OPENWEATHERMAP_API_KEY
20 | # +
21 | URL_MODE: str = '&units=metric&cnt=25&q='
22 | # +
23 | # city
24 |
25 | # fetch weather json data
26 | async def fetch(city: str) -> Union[dict, None]:
27 | headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'}
28 | async with aiohttp.ClientSession() as session:
29 | try:
30 | async with session.get(
31 | f'{URL_BASE}{API_KEY}{URL_MODE}{city}',
32 | headers=headers, timeout=10, ssl=False) as r:
33 | res = json.loads(await r.text())
34 | status = res['cod'].lower()
35 | assert status == '200' or status == '404'
36 | return res
37 | except Exception as e:
38 | logger.exception(e)
39 | return None
40 |
41 | # yields weather data
42 | def process_weatherdata(resJson: Union[dict, None]) -> str:
43 | if resJson is None:
44 | return 'Temperature data unavailable'
45 | if not 'list' in resJson.keys():
46 | return '也许地址有误?'+\
47 | ('','如果这地址是对的,私聊我订正BUG!')[random.choice([0,0,1])]
48 |
49 | # location data
50 | cityChart: dict = resJson['city']
51 | nation = cityChart['country']
52 | city = cityChart['name'].upper()
53 | timezone = cityChart['timezone']
54 | timediff = timedelta(seconds=timezone)
55 |
56 | heading = f'''[ALL TIMES LOCAL]
57 | region: {city}, {nation}
58 | '''
59 |
60 | def resGen():
61 | try:
62 | for j in range(0, 25, 4):
63 | directChart: dict = resJson['list'][j]
64 | mainChart = directChart['main']
65 | weatherChart = directChart['weather'][0]
66 | windChart = directChart['wind']
67 | # if tempMin and tempMax are same, only display one temp
68 | tempMin = mainChart['temp_min']
69 | tempMax = mainChart['temp_max']
70 | temp = f'{tempMin}°C' if tempMin == tempMax \
71 | else f'{tempMin}-{tempMax}°C'
72 | time = (datetime.utcfromtimestamp(directChart['dt']) + timediff) \
73 | .strftime('%Y-%m-%d %H:%M:%S')
74 | yield \
75 | f'''{time}: {weatherChart['main']} ({weatherChart['description']}), {temp}
76 | wind: {windChart['speed']}m/s ({windChart['deg']}°), humidity: {mainChart['humidity']}, pressure: {mainChart['pressure']}hPa'''
77 | except (IndexError, KeyError):
78 | pass
79 | return heading + '\n'.join(resGen())
80 |
81 | async def openweathermap_weather(city: str):
82 | return process_weatherdata(await fetch(city))
83 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | APScheduler>=3.6.3
2 | aiosqlite==0.17.0
3 | aiohttp>=3.5.4
4 | aiocqhttp>=1.2.3
5 | beautifulsoup4>=4.8.2
6 | nonebot>=1.5.0
7 | jieba==0.42.1
8 | pytz>=2019.3
9 | translate==3.5.0
10 |
11 |
--------------------------------------------------------------------------------
/utils_bot/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cleoold/sendo-erika/61dcc6d7e01a59e3f454a90e3b3094eb571ff312/utils_bot/__init__.py
--------------------------------------------------------------------------------
/utils_bot/command_ops.py:
--------------------------------------------------------------------------------
1 | from functools import wraps as _wraps
2 | from time import time as _time
3 |
4 | from nonebot import CommandSession as _CommandSession
5 | from nonebot import on_command as _on_command
6 | from nonebot.command import CommandHandler_T
7 | from nonebot.permission import GROUP_MEMBER, SUPERUSER
8 |
9 | from .logging import logger as _logger
10 | from .typing import Awaitable, Callable, Generator, Iterable
11 |
12 |
13 | # decorator
14 | def force_private(f: Callable[..., Awaitable]) -> Callable[..., Awaitable]:
15 | '''forces a command to be executed only in private chat
16 | :wrapped f's args[0]: must be a CommandSession
17 | '''
18 | @_wraps(f)
19 | async def wrapped(*args, **kwargs):
20 | session: _CommandSession = args[0]
21 | if session.event.get('group_id') or session.event.get('discuss_id'):
22 | _logger.info('forbidden private command terminated.')
23 | session.finish()
24 | else:
25 | return await f(*args, **kwargs)
26 | return wrapped
27 |
28 |
29 | def global_cooldown(cooldown: int) -> Callable[[Callable[..., Awaitable]], Callable[..., Awaitable]]:
30 | '''limit the rate of a command globally
31 | '''
32 | def deco(f: Callable[..., Awaitable]) -> Callable[..., Awaitable]:
33 | lastcall = 0.0
34 | @_wraps(f)
35 | async def wrapped(*args, **kwargs):
36 | session: _CommandSession = args[0]
37 | nonlocal lastcall
38 | if _time() - lastcall > cooldown:
39 | await f(*args, **kwargs)
40 | lastcall = _time()
41 | else:
42 | await session.send(f'技能冷却中…… ({cooldown}s)')
43 | return wrapped
44 | return deco
45 |
46 |
47 | ##############################################################################
48 | # these features are subject to low efficiencies, and generate
49 | # commands that might go beyond control. use at own risks
50 | # they are absolutely NOT RECOMMENDED in your implementations
51 | ## command generator
52 | def _names_after_q(names: Iterable[str]) -> Generator[str, None, None]:
53 | for each in names:
54 | yield each
55 | yield f'{each}?'
56 | yield f'{each}?'
57 |
58 | def _names_after_do(names: Iterable[str]) -> Generator[str, None, None]:
59 | for each in names:
60 | yield each
61 | yield f'{each}下'
62 | yield f'{each}一下'
63 | yield f'{each}吧'
64 |
65 | def _names_after_do2(names: Iterable[str]) -> Generator[str, None, None]:
66 | for each in names:
67 | yield each
68 | yield f'给我{each}'
69 | yield f'和我{each}'
70 | yield f'跟我{each}'
71 |
72 | # decorators
73 | def on_grp_command_ask(*names: str) -> Callable[[CommandHandler_T], CommandHandler_T]:
74 | '''default to group chat and superusers.
75 | automatically generates question marks after command names as aliases
76 | '''
77 | namesNew = _names_after_q(names)
78 | return _on_command(next(namesNew),
79 | aliases=(name for name in namesNew),
80 | permission=SUPERUSER | GROUP_MEMBER)
81 |
82 | def on_grp_command_do(*names: str) -> Callable[[CommandHandler_T], CommandHandler_T]:
83 | '''default to group chat and superusers.
84 | automatically generates some pre/suffixes as aliases
85 | '''
86 | namesNew = _names_after_do(names)
87 | namesNew = _names_after_do2(namesNew)
88 | namesNew = _names_after_q(namesNew)
89 | return _on_command(next(namesNew),
90 | aliases=(name for name in namesNew),
91 | permission=SUPERUSER | GROUP_MEMBER)
92 |
93 | def on_grp_command(*names: str) -> Callable[[CommandHandler_T], CommandHandler_T]:
94 | '''default to group chat and superusers.
95 | '''
96 | namesNew = iter(names)
97 | return _on_command(next(namesNew),
98 | aliases=(name for name in namesNew),
99 | permission=SUPERUSER | GROUP_MEMBER)
100 | ##############################################################################
101 |
--------------------------------------------------------------------------------
/utils_bot/datetime.py:
--------------------------------------------------------------------------------
1 | from datetime import *
2 |
3 | from pytz import timezone
4 |
5 | # all calls to datetime is associated with this timezone
6 | TZ = timezone('Asia/Shanghai')
7 |
--------------------------------------------------------------------------------
/utils_bot/logging.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import sys
3 |
4 | logger = logging.getLogger('sendoerika')
5 | handler = logging.StreamHandler(sys.stdout)
6 | handler.setFormatter(
7 | logging.Formatter('[%(asctime)s %(name)s] %(levelname)s: %(message)s'))
8 | logger.addHandler(handler)
9 | logger.setLevel(logging.INFO) # fixme
10 |
--------------------------------------------------------------------------------
/utils_bot/msg_ops.py:
--------------------------------------------------------------------------------
1 | from asyncio import gather as _gather
2 | from nonebot import get_bot as _get_bot
3 |
4 | bot = _get_bot()
5 | SUPERUSERS = bot.config.SUPERUSERS
6 | MY_NAMES = bot.config.NICKNAME.union({'机器人', '机械人', '复读机'})
7 |
8 | async def send_to_superusers(msg: str):
9 | tasks = [bot.send_private_msg(user_id=eachId, message=msg) for eachId in SUPERUSERS]
10 | await _gather(*tasks)
11 |
12 | def msg_is_calling_me(msg: str) -> bool:
13 | for myName in MY_NAMES:
14 | if myName in msg:
15 | return True
16 | return False
17 |
--------------------------------------------------------------------------------
/utils_bot/string_ops.py:
--------------------------------------------------------------------------------
1 | import random as _random
2 |
3 | from .typing import T, Sequence
4 |
5 | # fixes aligning problems for multibyte characters
6 | def my_ljust(s, n, fillchar=' ') -> str:
7 | 'same as ljust'
8 | return s.ljust(n - (len(s.encode("gbk")) - len(s)), fillchar)
9 |
10 | def my_rjust(s, n, fillchar=' ') -> str:
11 | 'same as rjust'
12 | return s.rjust(n - (len(s.encode("gbk")) - len(s)), fillchar)
13 |
14 | def half_none(s: str) -> str:
15 | 'half chance returning s, half chance returning empty string'
16 | return s if _random.choice((0,1,)) else ''
17 |
18 |
19 | def prob_pick(itera: Sequence[T], probs: Sequence[float]) -> T:
20 | ''''picks elements randomly from [iter] according to the cumulative
21 | probability array [probs] which has the same length and ranges from 0 to 1'''
22 | chosen: float = _random.random()
23 | if 0 <= chosen < probs[0]:
24 | return itera[0]
25 | for j in range(len(itera)-1):
26 | if probs[j] <= chosen < probs[j+1]:
27 | return itera[j+1]
28 | return itera[len(itera)-1]
29 |
--------------------------------------------------------------------------------
/utils_bot/typing.py:
--------------------------------------------------------------------------------
1 | from typing import *
2 |
3 | T = TypeVar('T')
4 |
5 | def depreciated(f: T) -> T:
6 | return f
7 |
--------------------------------------------------------------------------------