Browse Source

remote version 0.1.0

grayzhao 2 years ago
parent
commit
d8ee5c5307
39 changed files with 1193 additions and 0 deletions
  1. 8 0
      .idea/.gitignore
  2. 15 0
      .idea/deployment.xml
  3. 19 0
      .idea/inspectionProfiles/Project_Default.xml
  4. 6 0
      .idea/inspectionProfiles/profiles_settings.xml
  5. 4 0
      .idea/misc.xml
  6. 8 0
      .idea/modules.xml
  7. 8 0
      .idea/sheepBot.iml
  8. 17 0
      Dockerfile
  9. 12 0
      NoneBot/Dockerfile
  10. 50 0
      Python3.10.12/Dockerfile
  11. 6 0
      sheepBot/.env.dev
  12. 0 0
      sheepBot/.env.prod
  13. 141 0
      sheepBot/.gitignore
  14. 12 0
      sheepBot/README.md
  15. 48 0
      sheepBot/bot.py
  16. 14 0
      sheepBot/pyproject.toml
  17. 67 0
      sheepBot/src/plugins/60s News/__init__.py
  18. 25 0
      sheepBot/src/plugins/60s News/config.py
  19. 52 0
      sheepBot/src/plugins/60s News/data_source.py
  20. 59 0
      sheepBot/src/plugins/bing_scenery/__init__.py
  21. 13 0
      sheepBot/src/plugins/bing_scenery/config.py
  22. 41 0
      sheepBot/src/plugins/bing_scenery/data_source.py
  23. 54 0
      sheepBot/src/plugins/help_desc/__init__.py
  24. 5 0
      sheepBot/src/plugins/help_desc/config.py
  25. 39 0
      sheepBot/src/plugins/little_joke/__init__.py
  26. 5 0
      sheepBot/src/plugins/little_joke/config.py
  27. 38 0
      sheepBot/src/plugins/little_joke/data_source.py
  28. 59 0
      sheepBot/src/plugins/moyu_calendar/__init__.py
  29. 13 0
      sheepBot/src/plugins/moyu_calendar/config.py
  30. 53 0
      sheepBot/src/plugins/moyu_calendar/data_source.py
  31. 39 0
      sheepBot/src/plugins/scenic_photography/__init__.py
  32. 5 0
      sheepBot/src/plugins/scenic_photography/config.py
  33. 36 0
      sheepBot/src/plugins/scenic_photography/data_source.py
  34. 59 0
      sheepBot/src/plugins/today_in_history/__init__.py
  35. 13 0
      sheepBot/src/plugins/today_in_history/config.py
  36. 45 0
      sheepBot/src/plugins/today_in_history/data_source.py
  37. 61 0
      sheepBot/src/plugins/waste_sorting/__init__.py
  38. 5 0
      sheepBot/src/plugins/waste_sorting/config.py
  39. 39 0
      sheepBot/src/plugins/waste_sorting/data_source.py

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 15 - 0
.idea/deployment.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="PublishConfigData" autoUpload="Always" createEmptyFolders="true">
+    <serverData>
+      <paths name="sheepBot">
+        <serverdata>
+          <mappings>
+            <mapping deploy="/app" local="$PROJECT_DIR$" />
+          </mappings>
+        </serverdata>
+      </paths>
+    </serverData>
+    <option name="myAutoUpload" value="ALWAYS" />
+  </component>
+</project>

+ 19 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,19 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
+      <option name="ignoredErrors">
+        <list>
+          <option value="N801" />
+        </list>
+      </option>
+    </inspection_tool>
+    <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="ignoredIdentifiers">
+        <list>
+          <option value="resource.resource_rc" />
+        </list>
+      </option>
+    </inspection_tool>
+  </profile>
+</component>

+ 6 - 0
.idea/inspectionProfiles/profiles_settings.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="USE_PROJECT_PROFILE" value="false" />
+    <version value="1.0" />
+  </settings>
+</component>

+ 4 - 0
.idea/misc.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" project-jdk-name="Remote Python 3.10.12 (/bin/python)" project-jdk-type="Python SDK" />
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/sheepBot.iml" filepath="$PROJECT_DIR$/.idea/sheepBot.iml" />
+    </modules>
+  </component>
+</project>

+ 8 - 0
.idea/sheepBot.iml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="jdk" jdkName="Remote Python 3.10.12 (/bin/python)" jdkType="Python SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 17 - 0
Dockerfile

@@ -0,0 +1,17 @@
+# 设置基础镜像
+FROM grayzhao/nonebot:latest
+
+# 作者信息
+MAINTAINER GrayZhao "gray.zhao@qq.com"
+
+# 服务提供的外部端口号
+EXPOSE 8080
+
+# 工作目录
+WORKDIR /app/sheepBot
+
+# 挂载目录
+VOLUME /app
+
+# 启动 ssh 服务
+CMD ["/usr/bin/python", "bot.py"]

+ 12 - 0
NoneBot/Dockerfile

@@ -0,0 +1,12 @@
+# 设置基础镜像
+FROM grayzhao/python3.10.12
+
+# 作者信息
+MAINTAINER GrayZhao "gray.zhao@qq.com"
+
+# 安装依赖
+RUN bash -c "python -m pip install --upgrade pip; \
+    python -m pip install aiohttp; \
+    python -m pip install pipx; \
+    pipx ensurepath; \
+    pipx install nb-cli;"

+ 50 - 0
Python3.10.12/Dockerfile

@@ -0,0 +1,50 @@
+# 设置基础镜像
+FROM ubuntu:20.04
+
+# 作者信息
+MAINTAINER GrayZhao "gray.zhao@qq.com"
+
+# 设置上海时区
+ENV TZ='Asia/Shanghai' LANG=C.UTF-8
+
+# 配置镜像源,pip源,后面安装依赖时可以加快速度
+# 创建软链接,将Python3.10.12设置为python3,将Python3.10.12的pip3设置为pip3
+RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
+    sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \
+    apt-get update && apt-get upgrade -y && \
+    apt-get install -y openssh-server net-tools vim git wget curl make build-essential zlib1g-dev libncurses5-dev \
+    libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev libbz2-dev python-openssl
+
+
+# 下载并编译安装Python 3.10.12
+WORKDIR /tmp
+RUN wget https://www.python.org/ftp/python/3.10.12/Python-3.10.12.tgz && \
+    tar -zvxf Python-3.10.12.tgz && \
+    cd Python-3.10.12 && \
+    ./configure --enable-optimizations && \
+    make && \
+    make install && \
+    rm -rf /tmp/Python-3.10.12*
+
+# 设置 Python3 为默认的 python3 版本
+# 设置 pip3 为 Python3.10.12 的 pip3 版本
+# 配置镜像源,pip源
+RUN ln -sf /usr/local/bin/python3.10 /usr/bin/python && \
+    ln -sf /usr/local/bin/pip3.10 /usr/bin/pip && \
+    pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
+
+
+# 配置 ssh
+RUN bash -c "source ~/.bashrc; \
+    mkdir /var/run/sshd; \
+    echo 'root:sheepbot' | chpasswd; \
+    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config; \
+    echo 'PermitEmptyPasswords yes' >> /etc/ssh/sshd_config; \
+    echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config;"
+
+# 服务提供的外部端口号
+EXPOSE 22
+
+
+# 启动 ssh 服务
+CMD ["/usr/sbin/sshd", "-D"]

+ 6 - 0
sheepBot/.env.dev

@@ -0,0 +1,6 @@
+LOG_LEVEL=DEBUG
+HOST=0.0.0.0 # 配置 NoneBot 监听的 IP/主机名
+PORT=8080 # 配置 NoneBot 监听的端口 必须与config.yml中设置的端口号相同!!
+SUPERUSERS=["924868349"] # 配置 NoneBot 超级用户(哪些QQ可以管理该机器人)
+NICKNAME=["小白羊"] # 配置机器人的昵称,可以设置多个
+COMMAND_START=["/"] # 配置命令起始字符 以"/"开头表示对机器人发指令exit

+ 0 - 0
sheepBot/.env.prod


+ 141 - 0
sheepBot/.gitignore

@@ -0,0 +1,141 @@
+
+# Created by https://www.toptal.com/developers/gitignore/api/python
+# Edit at https://www.toptal.com/developers/gitignore?templates=python
+
+### Python ###
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+pytestdebug.log
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+doc/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# End of https://www.toptal.com/developers/gitignore/api/python

+ 12 - 0
sheepBot/README.md

@@ -0,0 +1,12 @@
+# sheepBot
+
+## How to start
+
+1. generate project using `nb create` .
+2. create your plugin using `nb plugin create` .
+3. writing your plugins under `src/plugins` folder.
+4. run your bot using `nb run --reload` .
+
+## Documentation
+
+See [Docs](https://v2.nonebot.dev/)

+ 48 - 0
sheepBot/bot.py

@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+""" 
+---------------------------------------
+ # @Project    : sheepBot
+ # @File       : bot.py
+ # @Author     : GrayZhao
+ # @Date       : 2023/7/4 18:01
+ # @Version    : 
+ # @Description : 
+---------------------------------------
+"""
+
+import nonebot
+from nonebot.adapters.onebot.v11 import Adapter as ONEBOT_V11Adapter
+
+# Custom your logger
+#
+# from nonebot.log import logger, default_format
+# logger.add("error.log",
+#            rotation="00:00",
+#            diagnose=False,
+#            level="ERROR",
+#            format=default_format)
+
+# You can pass some keyword args config to init function
+nonebot.init()
+app = nonebot.get_asgi()
+
+driver = nonebot.get_driver()
+driver.register_adapter(ONEBOT_V11Adapter)
+
+nonebot.load_builtin_plugins("echo")
+
+# Please DO NOT modify this file unless you know what you are doing!
+# As an alternative, you should use command `nb` or modify `pyproject.toml` to load plugins
+nonebot.load_from_toml("pyproject.toml")
+
+# Modify some config / config depends on loaded configs
+#
+# config = driver.config
+# do something...
+
+
+if __name__ == "__main__":
+    nonebot.logger.warning("Always use `nb run` to start the bot instead of manually running!")
+    nonebot.run(app="__mp_main__:app")

+ 14 - 0
sheepBot/pyproject.toml

@@ -0,0 +1,14 @@
+[project]
+name = "sheepBot"
+version = "0.1.0"
+description = "sheepBot"
+readme = "README.md"
+requires-python = ">=3.8, <4.0"
+
+[tool.nonebot]
+adapters = [
+    { name = "OneBot V11", module_name = "nonebot.adapters.onebot.v11" }
+]
+plugins = []
+plugin_dirs = ["src/plugins"]
+builtin_plugins = ["echo"]

+ 67 - 0
sheepBot/src/plugins/60s News/__init__.py

@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+""" 
+---------------------------------------
+ # @Project    : sheepBot
+ # @File       : __init__.py.py
+ # @Author     : GrayZhao
+ # @Date       : 2023/7/5 0:01
+ # @Version    : 
+ # @Description : 
+---------------------------------------
+"""
+
+from nonebot import on_command, require, get_driver, get_bot
+from nonebot.rule import T_State, to_me
+from nonebot.adapters.onebot.v11 import Bot, PrivateMessageEvent, GroupMessageEvent, Message
+from .config import Config
+from .data_source import get_60sNews
+
+__help_version__ = '0.1.0'
+__help_plugin_name__ = "60s"
+__usage__ = """每天60秒读懂世界
+
+使用:
+/60s|新闻:查看今天的60s新闻
+/60s|新闻+设置 小时:分钟:设置60s新闻的推送时间
+/60s|新闻+禁用:禁用60s新闻推送"""
+
+driver = get_driver()
+global_config = driver.config
+config = Config.parse_obj(global_config)
+nickname = list(global_config.nickname)[0]
+scheduler = require("nonebot_plugin_apscheduler").scheduler
+news60s = on_command("60s", aliases={"news", "新闻"}, rule=to_me(), priority=7, block=True)
+
+
+async def news60s_reminder():
+    bot = get_bot()
+    news = await get_60sNews()
+    for i in config.news60s_reminder_groups:
+        msg = f"「{nickname}·60s读懂世界」\n{news}"
+        await bot.call_api('send_group_msg', **{'group_id': i, 'message': Message(msg)})
+
+
+@news60s.handle()
+async def news60s_handle_group(bot: Bot, event: GroupMessageEvent, state: T_State):
+    news = await get_60sNews()
+    msg = f"「{nickname}·60s读懂世界」\n[CQ:at,qq={event.get_user_id()}]\n{news}"
+    await news60s.finish(Message(msg))
+
+
+@news60s.handle()
+async def news60s_handle_private(bot: Bot, event: PrivateMessageEvent, state: T_State):
+    news = await get_60sNews()
+    msg = f"「{nickname}·60s读懂世界」\n{news}"
+    await news60s.finish(Message(msg))
+
+
+@driver.on_startup
+async def _():
+    if config.news60s_reminder_start:
+        for i in range(len(config.news60s_reminder_time)):
+            temp = config.news60s_reminder_time[i].split(":")
+            hour = int(temp[0])
+            minute = int(temp[1])
+            scheduler.add_job(news60s_reminder, 'cron', hour=hour, minute=minute, id=f"news60s_reminder_{i}")

+ 25 - 0
sheepBot/src/plugins/60s News/config.py

@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+""" 
+---------------------------------------
+ # @Project    : sheepBot
+ # @File       : config.py
+ # @Author     : GrayZhao
+ # @Date       : 2023/7/5 0:03
+ # @Version    : 
+ # @Description : 
+---------------------------------------
+"""
+from pydantic import BaseModel, Extra
+
+
+class Config(BaseModel, extra=Extra.ignore):
+    # 定时提醒开关
+    news60s_reminder_start: bool = True
+
+    # 定时提醒推送的群号 605613804
+    news60s_reminder_groups: list = ["605613804", "703502878"]
+
+    # 定时提醒时间
+    news60s_reminder_time: list = ["08:00"]

+ 52 - 0
sheepBot/src/plugins/60s News/data_source.py

@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+""" 
+---------------------------------------
+ # @Project    : sheepBot
+ # @File       : data_source.py
+ # @Author     : GrayZhao
+ # @Date       : 2023/7/5 0:03
+ # @Version    : 
+ # @Description : 
+---------------------------------------
+"""
+import aiohttp
+import asyncio
+from nonebot import logger
+
+Headers = {
+    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
+}
+
+URL = "https://api.emoao.com/api/60s?type=json"
+
+
+async def fetch_final_url(url: str) -> str:
+    """获取直到不再跳转的url链接"""
+    async with aiohttp.ClientSession() as session:
+        while True:
+            async with session.get(url, allow_redirects=False) as response:
+                if response.status == 200:
+                    return response.url.human_repr()
+                elif response.status in [301, 302, 303, 307, 308]:
+                    url = response.headers.get('Location')
+                    if not url:
+                        return url
+                else:
+                    return url
+
+
+async def get_60sNews() -> str:
+    try:
+        async with aiohttp.ClientSession() as session:
+            async with session.get(url=URL, headers=Headers, timeout=5) as response:
+                res = await response.json(content_type=None)
+                data = res["data"]
+                img_url = await fetch_final_url(data["image"])
+                msg = f'[CQ:image,file={img_url},subType=0,cache=0]'
+                logger.debug(msg)
+                return msg
+    except:
+        logger.opt(exception=True).error("60秒读懂世界 - 获取信息失败")
+        return "抱歉,信息获取失败啦(っ °Д °;)っ"

+ 59 - 0
sheepBot/src/plugins/bing_scenery/__init__.py

@@ -0,0 +1,59 @@
+from nonebot import on_command, require, get_driver, get_bot
+from nonebot.rule import T_State, to_me
+from nonebot.plugin import PluginMetadata
+from nonebot.log import logger
+from nonebot.adapters.onebot.v11 import Bot, PrivateMessageEvent, GroupMessageEvent, Message
+from .config import Config
+from .data_source import get_bing_image
+
+
+__plugin_meta__ = PluginMetadata(
+    name="必应每日一图",
+    description="发送必应每日的一幅美图",
+    usage="必应每日一图 - 使用:/必应|每日一图",
+    config=Config,
+    extra={
+        "version": '0.1.0'
+    },
+)
+
+
+driver = get_driver()
+global_config = driver.config
+config = Config.parse_obj(global_config)
+nickname = list(global_config.nickname)[0]
+scheduler = require("nonebot_plugin_apscheduler").scheduler
+bing = on_command("每日一图", aliases={"必应", "bing"}, rule=to_me(), priority=7, block=True)
+
+
+async def bing_reminder():
+    bot = get_bot()
+    text = await get_bing_image()
+    for i in config.bing_reminder_groups:
+        msg = f"「{nickname}·必应每日一图」\n{text}"
+        await bot.call_api('send_group_msg', **{'group_id': i, 'message': Message(msg)})
+
+
+@bing.handle()
+async def bing_handle_group(bot: Bot, event: GroupMessageEvent, state: T_State):
+    text = await get_bing_image()
+    msg = f"「{nickname}·必应每日一图」\n[CQ:at,qq={event.get_user_id()}]\n{text}"
+    await bing.finish(Message(msg))
+
+
+@bing.handle()
+async def bing_handle_private(bot: Bot, event: PrivateMessageEvent, state: T_State):
+    text = await get_bing_image()
+    msg = f"「{nickname}·必应每日一图」\n{text}"
+    await bing.finish(Message(msg))
+
+
+@driver.on_startup
+async def _():
+    if config.bing_reminder_start:
+        for i in range(len(config.bing_reminder_time)):
+            temp = config.bing_reminder_time[i].split(":")
+            hour = int(temp[0])
+            minute = int(temp[1])
+            scheduler.add_job(bing_reminder, 'cron', hour=hour, minute=minute, id=f"bing_reminder_{i}")
+            logger.debug(f"定时启动,ID:bing_reminder_{i}, 定时->{hour}:{minute}")

+ 13 - 0
sheepBot/src/plugins/bing_scenery/config.py

@@ -0,0 +1,13 @@
+from pydantic import BaseModel, Extra
+
+
+class Config(BaseModel, extra=Extra.ignore):
+    """Plugin Config Here"""
+    # 定时提醒开关
+    bing_reminder_start: bool = True
+
+    # 定时提醒推送的群号 605613804
+    bing_reminder_groups: list = ["605613804", "703502878"]
+
+    # 定时提醒时间
+    bing_reminder_time: list = ["08:02"]

+ 41 - 0
sheepBot/src/plugins/bing_scenery/data_source.py

@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+""" 
+---------------------------------------
+ # @Project    : sheepBot
+ # @File       : data_source.py
+ # @Author     : GrayZhao
+ # @Date       : 2023/7/7 14:10
+ # @Version    : 
+ # @Description : 
+---------------------------------------
+"""
+import aiohttp
+import asyncio
+from nonebot import logger
+from urllib.parse import urljoin
+
+Headers = {
+    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
+}
+
+BASE_URL = "https://cn.bing.com"
+API_URL = urljoin(BASE_URL, "HPImageArchive.aspx?format=js&idx=0&n=1")
+
+
+async def get_bing_image() -> str:
+    try:
+        async with aiohttp.ClientSession() as session:
+            async with session.get(url=API_URL, headers=Headers, timeout=5) as response:
+                res = await response.json(content_type=None)
+                info = res["images"][0]
+                desc = info["copyright"]
+                param_url = info["url"]
+                img_url = urljoin(BASE_URL, param_url)
+                msg = f'{desc}\n\n[CQ:image,file={img_url},subType=0,cache=0]'
+                logger.debug(msg)
+                return msg
+    except:
+        logger.opt(exception=True).error("必应每日一图 - 获取信息失败")
+        return "抱歉,信息获取失败啦(っ °Д °;)っ"

+ 54 - 0
sheepBot/src/plugins/help_desc/__init__.py

@@ -0,0 +1,54 @@
+from nonebot import on_command, get_driver, get_bot
+from nonebot.rule import T_State, to_me
+from nonebot.plugin import PluginMetadata
+from nonebot.log import logger
+from nonebot.adapters.onebot.v11 import Bot, PrivateMessageEvent, GroupMessageEvent, Message
+from .config import Config
+
+
+__plugin_meta__ = PluginMetadata(
+    name="命令帮助",
+    description="机器人命令帮助",
+    usage="命令帮助 - 使用:/帮助|help",
+    config=Config,
+    extra={
+        "version": '0.1.0'
+    },
+)
+
+
+driver = get_driver()
+global_config = driver.config
+config = Config.parse_obj(global_config)
+nickname = list(global_config.nickname)[0]
+_help = on_command("命令帮助", aliases={"help", "帮助"}, rule=to_me(), priority=7, block=True)
+help_text = f"""[CQ:face,id=54] 群聊中需要 <@{nickname}> [CQ:face,id=54]
+
+* 📰 60秒读懂世界
+ - 使用:/60s|新闻
+* 🖼 必应每日一图
+ - 使用:/必应|每日一图
+* 📅 摸鱼人日历
+ - 使用:/摸鱼|moyu
+* ⏲ 历史上的今天
+ - 使用:/历史|历史上的今天
+* 🤣 随机一则笑话
+ - 使用:/笑话|joke
+* 🏞 随机一幅风景照
+ - 使用:/风景|scenic
+* ♻ 垃圾分类小助手
+ - 使用:/垃圾|垃圾分类 物品名称
+"""
+
+
+@_help.handle()
+async def _help_handle_group(bot: Bot, event: GroupMessageEvent, state: T_State):
+    msg = f"「{nickname}·命令」\n[CQ:at,qq={event.get_user_id()}]\n{help_text}"
+    await _help.finish(Message(msg))
+
+
+@_help.handle()
+async def _help_handle_private(bot: Bot, event: PrivateMessageEvent, state: T_State):
+    msg = f"「{nickname}·命令」\n{help_text}"
+    await _help.finish(Message(msg))
+

+ 5 - 0
sheepBot/src/plugins/help_desc/config.py

@@ -0,0 +1,5 @@
+from pydantic import BaseModel, Extra
+
+
+class Config(BaseModel, extra=Extra.ignore):
+    """Plugin Config Here"""

+ 39 - 0
sheepBot/src/plugins/little_joke/__init__.py

@@ -0,0 +1,39 @@
+from nonebot import on_command, get_driver, get_bot
+from nonebot.rule import T_State, to_me
+from nonebot.plugin import PluginMetadata
+from nonebot.log import logger
+from nonebot.adapters.onebot.v11 import Bot, PrivateMessageEvent, GroupMessageEvent, Message
+from .config import Config
+from .data_source import get_joke
+
+
+__plugin_meta__ = PluginMetadata(
+    name="随机一则笑话",
+    description="发送随机一则笑话",
+    usage="随机一则笑话 - 使用:/笑话|joke",
+    config=Config,
+    extra={
+        "version": '0.1.0'
+    },
+)
+
+
+driver = get_driver()
+global_config = driver.config
+config = Config.parse_obj(global_config)
+nickname = list(global_config.nickname)[0]
+joke = on_command("笑话", aliases={"joke", "一则笑话"}, rule=to_me(), priority=7, block=True)
+
+
+@joke.handle()
+async def joke_handle_group(bot: Bot, event: GroupMessageEvent, state: T_State):
+    text = await get_joke()
+    msg = f"「{nickname}·一则笑话」\n[CQ:at,qq={event.get_user_id()}]\n{text}"
+    await joke.finish(Message(msg))
+
+
+@joke.handle()
+async def joke_handle_private(bot: Bot, event: PrivateMessageEvent, state: T_State):
+    text = await get_joke()
+    msg = f"「{nickname}·一则笑话」\n{text}"
+    await joke.finish(Message(msg))

+ 5 - 0
sheepBot/src/plugins/little_joke/config.py

@@ -0,0 +1,5 @@
+from pydantic import BaseModel, Extra
+
+
+class Config(BaseModel, extra=Extra.ignore):
+    """Plugin Config Here"""

+ 38 - 0
sheepBot/src/plugins/little_joke/data_source.py

@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+""" 
+---------------------------------------
+ # @Project    : sheepBot
+ # @File       : data_source.py
+ # @Author     : GrayZhao
+ # @Date       : 2023/7/8 19:21
+ # @Version    : 
+ # @Description : 
+---------------------------------------
+"""
+import aiohttp
+import asyncio
+from nonebot import logger
+
+Headers = {
+    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
+}
+
+URL = "https://api.vvhan.com/api/joke?type=json"
+
+
+async def get_joke() -> str:
+    try:
+        async with aiohttp.ClientSession() as session:
+            async with session.get(url=URL, headers=Headers, timeout=5) as response:
+                res = await response.json(content_type=None)
+                title = res["title"]
+                joke = res["joke"]
+                msg = f'一则笑话:{title}\n\n{joke}'
+                logger.debug(msg)
+                return msg
+    except:
+        logger.opt(exception=True).error("随机笑话 - 获取信息失败")
+        return "抱歉,信息获取失败啦(っ °Д °;)っ"
+

+ 59 - 0
sheepBot/src/plugins/moyu_calendar/__init__.py

@@ -0,0 +1,59 @@
+from nonebot import on_command, require, get_driver, get_bot
+from nonebot.rule import T_State, to_me
+from nonebot.plugin import PluginMetadata
+from nonebot.log import logger
+from nonebot.adapters.onebot.v11 import Bot, PrivateMessageEvent, GroupMessageEvent, Message
+from .config import Config
+from .data_source import get_moyu
+
+
+__plugin_meta__ = PluginMetadata(
+    name="摸鱼人日历",
+    description="发送一幅摸鱼人日历",
+    usage="摸鱼人日历 - 使用:/摸鱼|moyu",
+    config=Config,
+    extra={
+        "version": '0.1.0'
+    },
+)
+
+
+driver = get_driver()
+global_config = driver.config
+config = Config.parse_obj(global_config)
+nickname = list(global_config.nickname)[0]
+scheduler = require("nonebot_plugin_apscheduler").scheduler
+moyu = on_command("摸鱼", aliases={"moyu", "摸鱼人日历"}, rule=to_me(), priority=7, block=True)
+
+
+async def moyu_reminder():
+    bot = get_bot()
+    text = await get_moyu()
+    for i in config.moyu_reminder_groups:
+        msg = f"「{nickname}·摸鱼人日历」\n{text}"
+        await bot.call_api('send_group_msg', **{'group_id': i, 'message': Message(msg)})
+
+
+@moyu.handle()
+async def moyu_handle_group(bot: Bot, event: GroupMessageEvent, state: T_State):
+    text = await get_moyu()
+    msg = f"「{nickname}·摸鱼人日历」\n[CQ:at,qq={event.get_user_id()}]\n{text}"
+    await moyu.finish(Message(msg))
+
+
+@moyu.handle()
+async def moyu_handle_private(bot: Bot, event: PrivateMessageEvent, state: T_State):
+    text = await get_moyu()
+    msg = f"「{nickname}·摸鱼人日历」\n{text}"
+    await moyu.finish(Message(msg))
+
+
+@driver.on_startup
+async def _():
+    if config.moyu_reminder_start:
+        for i in range(len(config.moyu_reminder_time)):
+            temp = config.moyu_reminder_time[i].split(":")
+            hour = int(temp[0])
+            minute = int(temp[1])
+            scheduler.add_job(moyu_reminder, 'cron', hour=hour, minute=minute, id=f"moyu_reminder_{i}")
+            logger.debug(f"定时启动,ID:moyu_reminder_{i}, 定时->{hour}:{minute}")

+ 13 - 0
sheepBot/src/plugins/moyu_calendar/config.py

@@ -0,0 +1,13 @@
+from pydantic import BaseModel, Extra
+
+
+class Config(BaseModel, extra=Extra.ignore):
+    """Plugin Config Here"""
+    # 定时提醒开关
+    moyu_reminder_start: bool = True
+
+    # 定时提醒推送的群号 605613804
+    moyu_reminder_groups: list = ["605613804", "703502878"]
+
+    # 定时提醒时间
+    moyu_reminder_time: list = ["08:01"]

+ 53 - 0
sheepBot/src/plugins/moyu_calendar/data_source.py

@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+""" 
+---------------------------------------
+ # @Project    : sheepBot
+ # @File       : data_source.py
+ # @Author     : GrayZhao
+ # @Date       : 2023/7/7 14:10
+ # @Version    : 
+ # @Description : 
+---------------------------------------
+"""
+import aiohttp
+import asyncio
+from nonebot import logger
+from nonebot.adapters.onebot.v11 import MessageSegment
+
+Headers = {
+    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
+}
+
+URL = "https://api.emoao.com/api/moyu?type=json"
+
+
+async def fetch_final_url(url: str) -> str:
+    """获取直到不再跳转的url链接"""
+    async with aiohttp.ClientSession() as session:
+        while True:
+            async with session.get(url, allow_redirects=False) as response:
+                if response.status == 200:
+                    return response.url.human_repr()
+                elif response.status in [301, 302, 303, 307, 308]:
+                    url = response.headers.get('Location')
+                    if not url:
+                        return url
+                else:
+                    return url
+
+
+async def get_moyu() -> str:
+    try:
+        async with aiohttp.ClientSession() as session:
+            async with session.get(url=URL, headers=Headers, timeout=5) as response:
+                res = await response.json(content_type=None)
+                title = res["title"]
+                img_url = await fetch_final_url(res["imgurl"])
+                msg = f'{title}\n\n{MessageSegment.image(img_url)}'
+                logger.debug(msg)
+                return msg
+    except:
+        logger.opt(exception=True).error("摸鱼人日历 - 获取信息失败")
+        return "抱歉,信息获取失败啦(っ °Д °;)っ"

+ 39 - 0
sheepBot/src/plugins/scenic_photography/__init__.py

@@ -0,0 +1,39 @@
+from nonebot import on_command, get_driver, get_bot
+from nonebot.rule import T_State, to_me
+from nonebot.plugin import PluginMetadata
+from nonebot.log import logger
+from nonebot.adapters.onebot.v11 import Bot, PrivateMessageEvent, GroupMessageEvent, Message
+from .config import Config
+from .data_source import get_photo
+
+
+__plugin_meta__ = PluginMetadata(
+    name="随机一幅风景照",
+    description="发送随机一幅风景照",
+    usage="随机一幅风景照 - 使用:/风景|scenic",
+    config=Config,
+    extra={
+        "version": '0.1.0'
+    },
+)
+
+
+driver = get_driver()
+global_config = driver.config
+config = Config.parse_obj(global_config)
+nickname = list(global_config.nickname)[0]
+scenic = on_command("风景", aliases={"scenic", "风景照"}, rule=to_me(), priority=7, block=True)
+
+
+@scenic.handle()
+async def scenic_handle_group(bot: Bot, event: GroupMessageEvent, state: T_State):
+    text = await get_photo()
+    msg = f"「{nickname}·风景照」\n[CQ:at,qq={event.get_user_id()}]\n{text}"
+    await scenic.finish(Message(msg))
+
+
+@scenic.handle()
+async def scenic_handle_private(bot: Bot, event: PrivateMessageEvent, state: T_State):
+    text = await get_photo()
+    msg = f"「{nickname}·风景照」\n{text}"
+    await scenic.finish(Message(msg))

+ 5 - 0
sheepBot/src/plugins/scenic_photography/config.py

@@ -0,0 +1,5 @@
+from pydantic import BaseModel, Extra
+
+
+class Config(BaseModel, extra=Extra.ignore):
+    """Plugin Config Here"""

+ 36 - 0
sheepBot/src/plugins/scenic_photography/data_source.py

@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+""" 
+---------------------------------------
+ # @Project    : sheepBot
+ # @File       : data_source.py
+ # @Author     : GrayZhao
+ # @Date       : 2023/7/8 19:21
+ # @Version    : 
+ # @Description : 
+---------------------------------------
+"""
+import aiohttp
+import asyncio
+from nonebot import logger
+
+Headers = {
+    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
+}
+
+URL = "https://api.gmit.vip/Api/FjImg?format=json"
+
+
+async def get_photo() -> str:
+    try:
+        async with aiohttp.ClientSession() as session:
+            async with session.get(url=URL, headers=Headers, timeout=5) as response:
+                res = await response.json(content_type=None)
+                img_url = res["data"]["url"]
+                msg = f'[CQ:image,file={img_url},subType=0,cache=0]'
+                logger.debug(msg)
+                return msg
+    except:
+        logger.opt(exception=True).error("风景照 - 获取信息失败")
+        return "抱歉,信息获取失败啦(っ °Д °;)っ"

+ 59 - 0
sheepBot/src/plugins/today_in_history/__init__.py

@@ -0,0 +1,59 @@
+from nonebot import on_command, require, get_driver, get_bot
+from nonebot.rule import T_State, to_me
+from nonebot.plugin import PluginMetadata
+from nonebot.log import logger
+from nonebot.adapters.onebot.v11 import Bot, PrivateMessageEvent, GroupMessageEvent, Message
+from .config import Config
+from .data_source import get_today_in_history
+
+
+__plugin_meta__ = PluginMetadata(
+    name="历史上的今天",
+    description="发送每日历史上的今天",
+    usage="历史上的今天 - 使用:/历史|历史上的今天",
+    config=Config,
+    extra={
+        "version": '0.1.0'
+    },
+)
+
+
+driver = get_driver()
+global_config = driver.config
+config = Config.parse_obj(global_config)
+nickname = list(global_config.nickname)[0]
+scheduler = require("nonebot_plugin_apscheduler").scheduler
+history = on_command("历史", aliases={"history", "历史上的今天"}, rule=to_me(), priority=7, block=True)
+
+
+async def history_reminder():
+    bot = get_bot()
+    text = await get_today_in_history()
+    for i in config.history_reminder_groups:
+        msg = f"「{nickname}·历史上的今天」\n{text}"
+        await bot.call_api('send_group_msg', **{'group_id': i, 'message': Message(msg)})
+
+
+@history.handle()
+async def history_handle_group(bot: Bot, event: GroupMessageEvent, state: T_State):
+    text = await get_today_in_history()
+    msg = f"「{nickname}·历史上的今天」\n[CQ:at,qq={event.get_user_id()}]\n{text}"
+    await history.finish(Message(msg))
+
+
+@history.handle()
+async def history_handle_private(bot: Bot, event: PrivateMessageEvent, state: T_State):
+    text = await get_today_in_history()
+    msg = f"「{nickname}·历史上的今天」\n{text}"
+    await history.finish(Message(msg))
+
+
+@driver.on_startup
+async def _():
+    if config.history_reminder_start:
+        for i in range(len(config.history_reminder_time)):
+            temp = config.history_reminder_time[i].split(":")
+            hour = int(temp[0])
+            minute = int(temp[1])
+            scheduler.add_job(history_reminder, 'cron', hour=hour, minute=minute, id=f"history_reminder_{i}")
+            logger.debug(f"定时启动,ID:history_reminder_{i}, 定时->{hour}:{minute}")

+ 13 - 0
sheepBot/src/plugins/today_in_history/config.py

@@ -0,0 +1,13 @@
+from pydantic import BaseModel, Extra
+
+
+class Config(BaseModel, extra=Extra.ignore):
+    """Plugin Config Here"""
+    # 定时提醒开关
+    history_reminder_start: bool = True
+
+    # 定时提醒推送的群号 605613804
+    history_reminder_groups: list = ["605613804", "703502878"]
+
+    # 定时提醒时间
+    history_reminder_time: list = ["08:03"]

+ 45 - 0
sheepBot/src/plugins/today_in_history/data_source.py

@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+""" 
+---------------------------------------
+ # @Project    : sheepBot
+ # @File       : data_source.py
+ # @Author     : GrayZhao
+ # @Date       : 2023/7/6 23:51
+ # @Version    : 
+ # @Description : 
+---------------------------------------
+"""
+import aiohttp
+import asyncio
+from nonebot import logger
+
+Headers = {
+    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
+}
+
+URL = "https://api.emoao.com/api/lsjr"
+
+
+async def get_today_in_history() -> str:
+    try:
+        async with aiohttp.ClientSession() as session:
+            async with session.get(url=URL, headers=Headers, timeout=5) as response:
+                res = await response.json(content_type=None)
+                day = res["day"]
+                results = res["result"]
+                msg = f'今天是:{day}\n\n\n'
+                interval = len(results) - 1
+                count = 0
+                for element in results:
+                    line = f'{element["year"]} - {element["title"]}'
+                    msg = msg + line
+                    count += 1
+                    if count <= interval:
+                        msg = msg + "\n\n"
+                logger.debug(msg)
+                return msg
+    except:
+        logger.opt(exception=True).error("历史上的今天 - 获取信息失败")
+        return "抱歉,信息获取失败啦(っ °Д °;)っ"

+ 61 - 0
sheepBot/src/plugins/waste_sorting/__init__.py

@@ -0,0 +1,61 @@
+from nonebot import on_command, get_driver, get_bot
+from nonebot.rule import T_State, to_me
+from nonebot.plugin import PluginMetadata
+from nonebot.params import CommandArg, ArgPlainText
+from nonebot.matcher import Matcher
+from nonebot.log import logger
+from nonebot.adapters.onebot.v11 import Bot, PrivateMessageEvent, GroupMessageEvent, Message
+from .config import Config
+from .data_source import get_sorted
+
+
+__plugin_meta__ = PluginMetadata(
+    name="垃圾分类",
+    description="垃圾分类小助手,帮助你快速分类垃圾",
+    usage="垃圾分类小助手 - 使用:/垃圾|垃圾分类 物品名称",
+    config=Config,
+    extra={
+        "version": '0.1.0'
+    },
+)
+
+
+driver = get_driver()
+global_config = driver.config
+config = Config.parse_obj(global_config)
+nickname = list(global_config.nickname)[0]
+waste = on_command("垃圾", aliases={"waste", "垃圾分类"}, rule=to_me(), priority=7, block=True)
+
+
+# @waste.handle()
+# async def waste_handle_group(bot: Bot, event: GroupMessageEvent, state: T_State, args: Message = CommandArg()):
+#     if name := args.extract_plain_text():
+#         text = await get_sorted(name)
+#         msg = f"「{nickname}·垃圾分类」\n[CQ:at,qq={event.get_user_id()}]\n{text}"
+#         await waste.finish(Message(msg))
+
+
+@waste.handle()
+async def waste_handle_group(event: GroupMessageEvent, matcher: Matcher, args: Message = CommandArg()):
+    if args.extract_plain_text():
+        matcher.set_arg("name", args)
+
+
+@waste.got("name", prompt="请输入需要查询分类的物品名称")
+async def waste_got_group(bot: Bot, event: GroupMessageEvent, state: T_State, name: str = ArgPlainText()):
+    text = await get_sorted(name)
+    msg = f"「{nickname}·垃圾分类」\n[CQ:at,qq={event.get_user_id()}]\n{text}"
+    await waste.finish(Message(msg))
+
+
+@waste.handle()
+async def waste_handle_private(event: PrivateMessageEvent, matcher: Matcher, args: Message = CommandArg()):
+    if args.extract_plain_text():
+        matcher.set_arg("name", args)
+
+
+@waste.got("name", prompt="请输入需要查询分类的物品名称")
+async def waste_got_private(bot: Bot, event: PrivateMessageEvent, state: T_State, name: str = ArgPlainText()):
+    text = await get_sorted(name)
+    msg = f"「{nickname}·垃圾分类」\n{text}"
+    await waste.finish(Message(msg))

+ 5 - 0
sheepBot/src/plugins/waste_sorting/config.py

@@ -0,0 +1,5 @@
+from pydantic import BaseModel, Extra
+
+
+class Config(BaseModel, extra=Extra.ignore):
+    """Plugin Config Here"""

+ 39 - 0
sheepBot/src/plugins/waste_sorting/data_source.py

@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+""" 
+---------------------------------------
+ # @Project    : sheepBot
+ # @File       : data_source.py
+ # @Author     : GrayZhao
+ # @Date       : 2023/7/8 19:21
+ # @Version    : 
+ # @Description : 
+---------------------------------------
+"""
+import aiohttp
+import asyncio
+from nonebot import logger
+from urllib.parse import urljoin, quote
+
+Headers = {
+    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
+}
+
+BASE_URL = "https://api.vvhan.com/api/la.ji"
+
+
+async def get_sorted(name: str) -> str:
+    try:
+        async with aiohttp.ClientSession() as session:
+            _url = urljoin(BASE_URL, f"?lj={quote(name)}")
+            async with session.get(url=_url, headers=Headers, timeout=5) as response:
+                res = await response.json(content_type=None)
+                sort_name = res["sort"]
+                msg = f'🗑 物品:{name}\n\n♻ 分类:{sort_name}'
+                logger.debug(msg)
+                return msg
+    except:
+        logger.opt(exception=True).error("垃圾分类 - 获取信息失败")
+        return "抱歉,信息获取失败啦(っ °Д °;)っ"
+