feat: 轻雪天气实时天气功能已更新
@ -8,14 +8,20 @@ category: 使用手册
|
||||
|
||||
## 功能插件命令
|
||||
|
||||
### 轻雪天气`liteyuki_weather`
|
||||
### **轻雪天气`liteyuki_weather`**
|
||||
配置项
|
||||
```yaml
|
||||
weather-key # 和风天气的天气key
|
||||
weather_key: "" # 和风天气的天气key
|
||||
weather_dev: false # 是否为开发版
|
||||
```
|
||||
|
||||
命令
|
||||
```shell
|
||||
weather <keywords...> # 查询目标地实时天气,例如:"天气 北京 海淀", "weather Tokyo Shinjuku"
|
||||
bind-city <keywords...> # 绑定查询城市,个人全局生效
|
||||
别名:weather 天气
|
||||
```
|
||||
|
||||
命令别名
|
||||
```shell
|
||||
weather 天气, bind-city 绑定城市
|
||||
```
|
@ -65,12 +65,18 @@ async def _(bot: T_Bot, event: T_MessageEvent):
|
||||
async def _(matcher: Matcher, bot: T_Bot, event: T_MessageEvent):
|
||||
await matcher.send("Liteyuki reloading")
|
||||
temp_data = common_db.first(TempConfig(), default=TempConfig())
|
||||
temp_data.data["reload"] = True
|
||||
temp_data.data["reload_time"] = time.time()
|
||||
temp_data.data["reload_bot_id"] = bot.self_id
|
||||
temp_data.data["reload_session_type"] = event.message_type
|
||||
temp_data.data["reload_session_id"] = event.group_id if event.message_type == "group" else event.user_id
|
||||
temp_data.data["delta_time"] = 0
|
||||
|
||||
temp_data.data.update(
|
||||
{
|
||||
"reload" : True,
|
||||
"reload_time" : time.time(),
|
||||
"reload_bot_id" : bot.self_id,
|
||||
"reload_session_type": event.message_type,
|
||||
"reload_session_id" : event.group_id if event.message_type == "group" else event.user_id,
|
||||
"delta_time" : 0
|
||||
}
|
||||
)
|
||||
|
||||
common_db.upsert(temp_data)
|
||||
Reloader.reload(0)
|
||||
|
||||
@ -88,7 +94,12 @@ async def _(matcher: Matcher, bot: T_Bot, event: T_MessageEvent):
|
||||
Subcommand(
|
||||
"get",
|
||||
Args["key", str, None],
|
||||
alias=["查询"]
|
||||
alias=["查询", "获取"]
|
||||
),
|
||||
Subcommand(
|
||||
"remove",
|
||||
Args["key", str],
|
||||
alias=["删除"]
|
||||
)
|
||||
),
|
||||
permission=SUPERUSER
|
||||
@ -120,9 +131,17 @@ async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot, matcher: Matcher
|
||||
if len(stored_config.config) > 0:
|
||||
reply += f"\n{ulang.get('liteyuki.stored_config')}\n```dotenv"
|
||||
for k, v in stored_config.config.items():
|
||||
reply += f"\n{k}={v}"
|
||||
reply += f"\n{k}={v} {type(v)}"
|
||||
reply += "\n```"
|
||||
await md.send_md(reply, bot, event=event)
|
||||
elif result.subcommands.get("remove"):
|
||||
key = result.subcommands.get("remove").args.get("key")
|
||||
if key in stored_config.config:
|
||||
stored_config.config.pop(key)
|
||||
common_db.upsert(stored_config)
|
||||
await matcher.finish(f"{ulang.get('liteyuki.config_remove_success', KEY=key)}")
|
||||
else:
|
||||
await matcher.finish(f"{ulang.get('liteyuki.invalid_command', TEXT=key)}")
|
||||
|
||||
|
||||
@on_alconna(
|
||||
@ -227,6 +246,6 @@ async def every_day_update():
|
||||
if result:
|
||||
await broadcast_to_superusers(f"Liteyuki updated: ```\n{logs}\n```")
|
||||
nonebot.logger.info(f"Liteyuki updated: {logs}")
|
||||
Reloader.reload(1)
|
||||
Reloader.reload(5)
|
||||
else:
|
||||
nonebot.logger.info(logs)
|
||||
|
@ -35,7 +35,6 @@ async def _(bot: T_Bot, event: T_MessageEvent):
|
||||
{
|
||||
"data": await get_stats_data(bot.self_id, ulang.lang_code)
|
||||
},
|
||||
debug=True,
|
||||
wait=1
|
||||
)
|
||||
await stats.finish(MessageSegment.image(image))
|
||||
|
@ -0,0 +1,142 @@
|
||||
from .qw_models import *
|
||||
import httpx
|
||||
|
||||
language_map = {
|
||||
"zh-CN" : "zh",
|
||||
"zh-HK" : "zh-hant",
|
||||
"en-US" : "en",
|
||||
"ja-JP" : "ja",
|
||||
"ko-KR" : "ko",
|
||||
"fr-FR" : "fr",
|
||||
"es-ES" : "es",
|
||||
"de-DE" : "de",
|
||||
"it-IT" : "it",
|
||||
"ru-RU" : "ru",
|
||||
"ar-SA" : "ar",
|
||||
"pt-BR" : "pt",
|
||||
"nl-NL" : "nl",
|
||||
"pl-PL" : "pl",
|
||||
"tr-TR" : "tr",
|
||||
"th-TH" : "th",
|
||||
"vi-VN" : "vi",
|
||||
"id-ID" : "id",
|
||||
"ms-MY" : "ms",
|
||||
"fil-PH": "fil",
|
||||
} # 其他使用默认对应
|
||||
|
||||
dev_url = "https://devapi.qweather.com/" # 开发HBa
|
||||
com_url = "https://api.qweather.com/" # 正式环境
|
||||
|
||||
|
||||
async def city_lookup(
|
||||
location: str,
|
||||
key: str,
|
||||
adm: str = "",
|
||||
number: int = 20,
|
||||
lang: str = "zh",
|
||||
) -> CityLookup:
|
||||
"""
|
||||
通过关键字搜索城市信息
|
||||
Args:
|
||||
location:
|
||||
key:
|
||||
adm:
|
||||
number:
|
||||
lang: 可传入标准i18n语言代码,如zh-CN、en-US等
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
url = "https://geoapi.qweather.com/v2/city/lookup?"
|
||||
params = {
|
||||
"location": location,
|
||||
"adm" : adm,
|
||||
"number" : number,
|
||||
"key" : key,
|
||||
"lang" : language_map.get(lang, lang),
|
||||
}
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(url, params=params)
|
||||
return CityLookup.parse_obj(resp.json())
|
||||
|
||||
|
||||
async def get_weather_now(
|
||||
key: str,
|
||||
location: str,
|
||||
lang: str = "zh",
|
||||
unit: str = "m",
|
||||
dev: bool = True,
|
||||
) -> dict:
|
||||
url_path = "v7/weather/now?"
|
||||
url = dev_url + url_path if dev else com_url + url_path
|
||||
params = {
|
||||
"location": location,
|
||||
"key" : key,
|
||||
"lang" : language_map.get(lang, lang),
|
||||
"unit" : unit,
|
||||
}
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(url, params=params)
|
||||
return resp.json()
|
||||
|
||||
|
||||
async def get_weather_daily(
|
||||
key: str,
|
||||
location: str,
|
||||
lang: str = "zh",
|
||||
unit: str = "m",
|
||||
dev: bool = True,
|
||||
) -> dict:
|
||||
url_path = "v7/weather/%dd?" % (7 if dev else 30)
|
||||
url = dev_url + url_path if dev else com_url + url_path
|
||||
params = {
|
||||
"location": location,
|
||||
"key" : key,
|
||||
"lang" : language_map.get(lang, lang),
|
||||
"unit" : unit,
|
||||
}
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(url, params=params)
|
||||
return resp.json()
|
||||
|
||||
|
||||
async def get_weather_hourly(
|
||||
key: str,
|
||||
location: str,
|
||||
lang: str = "zh",
|
||||
unit: str = "m",
|
||||
dev: bool = True,
|
||||
) -> dict:
|
||||
url_path = "v7/weather/%dh?" % (24 if dev else 168)
|
||||
url = dev_url + url_path if dev else com_url + url_path
|
||||
params = {
|
||||
"location": location,
|
||||
"key" : key,
|
||||
"lang" : language_map.get(lang, lang),
|
||||
"unit" : unit,
|
||||
}
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(url, params=params)
|
||||
return resp.json()
|
||||
|
||||
|
||||
async def get_airquality(
|
||||
key: str,
|
||||
location: str,
|
||||
lang: str,
|
||||
pollutant: bool = False,
|
||||
station: bool = False,
|
||||
dev: bool = True
|
||||
) -> dict:
|
||||
url_path = f"airquality/v1/now/{location}?"
|
||||
url = dev_url + url_path if dev else com_url + url_path
|
||||
params = {
|
||||
"key" : key,
|
||||
"lang" : language_map.get(lang, lang),
|
||||
"pollutant": pollutant,
|
||||
"station" : station,
|
||||
}
|
||||
async with httpx.AsyncClient() as client:
|
||||
resp = await client.get(url, params=params)
|
||||
return resp.json()
|
||||
|
@ -19,12 +19,12 @@ class Location(LiteModel):
|
||||
license: str = ""
|
||||
|
||||
|
||||
class CityLookupResponse(LiteModel):
|
||||
class CityLookup(LiteModel):
|
||||
code: str = ""
|
||||
location: Location = Location()
|
||||
location: list[Location] = [Location()]
|
||||
|
||||
|
||||
class WeatherNow(LiteModel):
|
||||
class Now(LiteModel):
|
||||
obsTime: str = ""
|
||||
temp: str = ""
|
||||
feelsLike: str = ""
|
||||
@ -44,8 +44,19 @@ class WeatherNow(LiteModel):
|
||||
license: str = ""
|
||||
|
||||
|
||||
class WeatherNowResponse(LiteModel):
|
||||
class WeatherNow(LiteModel):
|
||||
code: str = ""
|
||||
updateTime: str = ""
|
||||
fxLink: str = ""
|
||||
now: WeatherNow = WeatherNow()
|
||||
now: Now = Now()
|
||||
|
||||
|
||||
class Daily(LiteModel):
|
||||
pass
|
||||
|
||||
|
||||
class WeatherDaily(LiteModel):
|
||||
code: str = ""
|
||||
updateTime: str = ""
|
||||
fxLink: str = ""
|
||||
daily: list[str] = []
|
@ -1,7 +1,16 @@
|
||||
from nonebot import require
|
||||
from nonebot.adapters.onebot.v11 import MessageSegment
|
||||
from nonebot.internal.matcher import Matcher
|
||||
|
||||
from liteyuki.utils.base.config import get_config
|
||||
from liteyuki.utils.base.ly_typing import T_MessageEvent
|
||||
|
||||
from .qw_api import *
|
||||
from ...utils.base.data_manager import User, user_db
|
||||
from ...utils.base.language import get_user_lang
|
||||
from ...utils.base.resource import get_path
|
||||
from ...utils.message.html_tool import template2image
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
from nonebot_plugin_alconna import on_alconna, Alconna, Args, MultiVar, Arparma
|
||||
|
||||
@ -10,11 +19,67 @@ from nonebot_plugin_alconna import on_alconna, Alconna, Args, MultiVar, Arparma
|
||||
aliases={"天气"},
|
||||
command=Alconna(
|
||||
"weather",
|
||||
Args["keywords", MultiVar(str)],
|
||||
Args["keywords", MultiVar(str), []],
|
||||
),
|
||||
).handle()
|
||||
async def _(result: Arparma, event: T_MessageEvent):
|
||||
async def _(result: Arparma, event: T_MessageEvent, matcher: Matcher):
|
||||
"""await alconna.send("weather", city)"""
|
||||
print(result["keywords"])
|
||||
if len(result["keywords"]) == 0:
|
||||
pass
|
||||
ulang = get_user_lang(str(event.user_id))
|
||||
qw_lang = language_map.get(ulang.lang_code, ulang.lang_code)
|
||||
key = get_config("weather_key")
|
||||
is_dev = get_config("weather_dev")
|
||||
user: User = user_db.first(User(), "user_id = ?", str(event.user_id), default=User())
|
||||
|
||||
# params
|
||||
unit = user.profile.get("unit", "m")
|
||||
stored_location = user.profile.get("location", None)
|
||||
|
||||
if not key:
|
||||
await matcher.finish(ulang.get("weather.no_key"))
|
||||
|
||||
kws = result.main_args.get("keywords")
|
||||
|
||||
if kws:
|
||||
if len(kws) >= 2:
|
||||
adm = kws[0]
|
||||
city = kws[-1]
|
||||
else:
|
||||
adm = ""
|
||||
city = kws[0]
|
||||
city_info = await city_lookup(city, key, adm=adm, lang=qw_lang)
|
||||
city_name = " ".join(kws)
|
||||
else:
|
||||
if not stored_location:
|
||||
await matcher.finish(ulang.get("liteyuki.invalid_command", TEXT="location"))
|
||||
city_info = await city_lookup(stored_location, key, lang=qw_lang)
|
||||
city_name = stored_location
|
||||
|
||||
if city_info.code == "200":
|
||||
location_data = city_info.location[0]
|
||||
else:
|
||||
await matcher.finish(ulang.get("weather.city_not_found", CITY=city_name))
|
||||
|
||||
weather_now = await get_weather_now(key, location_data.id, lang=qw_lang, unit=unit, dev=is_dev)
|
||||
weather_daily = await get_weather_daily(key, location_data.id, lang=qw_lang, unit=unit, dev=is_dev)
|
||||
weather_hourly = await get_weather_hourly(key, location_data.id, lang=qw_lang, unit=unit, dev=is_dev)
|
||||
aqi = await get_airquality(key, location_data.id, lang=qw_lang, dev=is_dev)
|
||||
|
||||
image = await template2image(
|
||||
template=get_path("templates/weather_now.html", abs_path=True),
|
||||
templates={
|
||||
"data": {
|
||||
"params" : {
|
||||
"unit": unit,
|
||||
"lang": ulang.lang_code,
|
||||
},
|
||||
"weatherNow" : weather_now,
|
||||
"weatherDaily" : weather_daily,
|
||||
"weatherHourly": weather_hourly,
|
||||
"aqi" : aqi,
|
||||
"location" : location_data.dump(),
|
||||
}
|
||||
},
|
||||
debug=True,
|
||||
wait=1
|
||||
)
|
||||
await matcher.finish(MessageSegment.image(image))
|
||||
|
@ -24,7 +24,7 @@ liteyuki.stats.friends=好友
|
||||
liteyuki.stats.plugins=插件
|
||||
liteyuki.image_mode_on=开启Markdown图片模式
|
||||
liteyuki.image_mode_off=关闭Markdown图片模式
|
||||
liteyuki.invalid_command=无效的命令或参数
|
||||
liteyuki.invalid_command=无效的命令或参数 {TEXT}
|
||||
liteyuki.reload_resources=重载资源
|
||||
liteyuki.list_resources=资源包列表
|
||||
liteyuki.reload_resources_success=资源重载成功,共计 {NUM} 个资源包
|
||||
@ -44,6 +44,7 @@ liteyuki.change_priority_failed=资源包 {NAME} 优先级修改失败
|
||||
liteyuki.group_already=群 {GROUP} 已经是 {STATUS} 状态,无需重复操作
|
||||
liteyuki.group_success=群 {GROUP} {STATUS} 成功
|
||||
liteyuki.permission_denied=权限不足
|
||||
liteyuki.config_remove_success=配置项 {KEY} 移除成功
|
||||
|
||||
main.current_language=当前配置语言为: {LANG}
|
||||
main.enable_webdash=已启用网页监控面板: {URL}
|
||||
@ -120,4 +121,8 @@ user.profile.set_failed=设置 {ATTR} 失败,请检查输入是否合法
|
||||
|
||||
rpm.move_up=上移
|
||||
rpm.move_down=下移
|
||||
rpm.move_top=置顶
|
||||
rpm.move_top=置顶
|
||||
|
||||
weather.city_not_found=未找到城市 {CITY}
|
||||
weather.weather_not_found=未找到城市 {CITY} 的天气信息
|
||||
weather.no_key=未设置天气api key,请在配置文件添加weather-key
|
@ -1,4 +1,4 @@
|
||||
#data-storage {
|
||||
.data-storage {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ body {
|
||||
background-repeat: repeat-y;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
text-shadow: 1px 1px 2px black;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,6 @@
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
body {
|
||||
* {
|
||||
font-family: 'MapleMono', 'MiSans', sans-serif;
|
||||
}
|
83
liteyuki/resources/templates/css/weather_now.css
Normal file
@ -0,0 +1,83 @@
|
||||
#weather-info {
|
||||
color: white;
|
||||
/*justify-content: center;*/
|
||||
/*align-items: center;*/
|
||||
/*align-content: center;*/
|
||||
}
|
||||
|
||||
#main-info {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#time {
|
||||
font-size: 25px;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
text-align: right;
|
||||
color: #aaa;
|
||||
|
||||
}
|
||||
|
||||
#adm {
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
#city {
|
||||
margin-top: 20px;
|
||||
font-size: 70px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#temperature {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
}
|
||||
|
||||
#temperature-now {
|
||||
font-size: 70px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#temperature-range {
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
#description {
|
||||
font-size: 50px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
#aqi {
|
||||
height: 50px;
|
||||
display: flex;
|
||||
border-radius: 60px;
|
||||
padding: 5px;
|
||||
font-size: 40px;
|
||||
text-align: center;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#aqi-dot {
|
||||
height: 80%;
|
||||
aspect-ratio: 1 / 1;
|
||||
border-radius: 50%;
|
||||
background-color: #aaa;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.main-icon {
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
}
|
BIN
liteyuki/resources/templates/img/qw_icon/100.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/101.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/102.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/103.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/104.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/150.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/151.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/152.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/153.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/154.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/300.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/301.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/302.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/303.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/304.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/305.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/306.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/307.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/308.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/309.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/310.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/311.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/312.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/313.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/314.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/315.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/316.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/317.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/318.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/350.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/351.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/399.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/400.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/401.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/402.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/403.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/404.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/405.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/406.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/407.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/408.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/409.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/410.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/456.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/457.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/499.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/500.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/501.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/502.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/503.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/504.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/507.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/508.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/509.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/510.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/511.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/512.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/513.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/514.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/515.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/800.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/801.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/802.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/803.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/804.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/805.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/806.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/807.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/900.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/901.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
liteyuki/resources/templates/img/qw_icon/999.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
59
liteyuki/resources/templates/js/weather_now.js
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @typedef {Object} Location
|
||||
* @property {string} city - The city name.
|
||||
* @property {string} country - The country name.
|
||||
*
|
||||
* @typedef {Object} Weather
|
||||
* @property {number} temperature - The current temperature.
|
||||
* @property {string} description - The weather description.
|
||||
*
|
||||
* @typedef {Object} Data
|
||||
* @property {Location} location - The location data.
|
||||
* @property {Weather} weather - The weather data.
|
||||
*/
|
||||
|
||||
/** @type {Data} */
|
||||
|
||||
let data = JSON.parse(document.getElementById("data").innerText)
|
||||
|
||||
let weatherNow = data["weatherNow"]
|
||||
|
||||
let weatherDaily = data["weatherDaily"]
|
||||
let weatherHourly = data["weatherHourly"]
|
||||
let aqi = data["aqi"]
|
||||
|
||||
let locationData = data["location"]
|
||||
|
||||
// set info
|
||||
// document.getElementById("time").innerText = weatherNow["now"]["obsTime"]
|
||||
// document.getElementById("city").innerText = locationData["name"]
|
||||
// document.getElementById("adm").innerText = locationData["country"] + " " + locationData["adm1"] + " " + locationData["adm2"]
|
||||
// document.getElementById("temperature-now").innerText = weatherNow["now"]["temp"] + "°"
|
||||
// document.getElementById("temperature-range").innerText = weatherNow["now"]["feelsLike"] + "°"
|
||||
// document.getElementById("description").innerText = weatherNow["now"]["text"]
|
||||
// 处理aqi
|
||||
let aqiValue = 0
|
||||
aqi["aqi"].forEach(
|
||||
(item) => {
|
||||
if (item["defaultLocalAqi"]) {
|
||||
document.getElementById("aqi-data").innerText = "AQI " + item["valueDisplay"] + " " + item["category"]
|
||||
// 将(255,255,255)这种格式的颜色设置给css
|
||||
document.getElementById("aqi-dot").style.backgroundColor = "rgb(" + item["color"] + ")"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
templates = {
|
||||
"time": weatherNow["now"]["obsTime"],
|
||||
"city": locationData["name"],
|
||||
"adm": locationData["country"] + " " + locationData["adm1"] + " " + locationData["adm2"],
|
||||
"temperature-now": weatherNow["now"]["temp"] + "°",
|
||||
"temperature-range": weatherDaily["daily"][0]["tempMin"] + "°/" + weatherDaily["daily"][0]["tempMax"] + "°",
|
||||
"description": weatherNow["now"]["text"]
|
||||
}
|
||||
|
||||
// 遍历每一个id,给其赋值
|
||||
|
||||
for (let id in templates) {
|
||||
document.getElementById(id).innerText = templates[id]
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Liteyuki Status</title>
|
||||
|
@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Liteyuki Status</title>
|
||||
<link rel="stylesheet" href="./css/card.css">
|
||||
<link rel="stylesheet" href="./css/fonts.css">
|
||||
<link rel="stylesheet" href="./css/weather_now.css">
|
||||
</head>
|
||||
<!-- qw_icon: https://a.hecdn.net/img/common/icon/202106d/%d.png-->
|
||||
<body>
|
||||
<div class="data-storage" id="data">{{ data | tojson }}</div>
|
||||
<div class="info-box" id="weather-info">
|
||||
<div id="detail-info">
|
||||
<div id="time">1145-01-12 22:22:22</div>
|
||||
<div id="adm">国家 一级 二级</div>
|
||||
<div id="city">城市</div>
|
||||
</div>
|
||||
<div id="main-info">
|
||||
<div>
|
||||
<img class="main-icon" src="./img/qw_icon/101.png" alt="AAA">
|
||||
</div>
|
||||
<div>
|
||||
<div id="temperature">
|
||||
<div id="temperature-now">
|
||||
90°
|
||||
</div>
|
||||
<div id="temperature-range">
|
||||
10°~90°
|
||||
</div>
|
||||
</div>
|
||||
<div id="description">
|
||||
好天气
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="aqi">
|
||||
<div id="aqi-dot"></div>
|
||||
<div id="aqi-data"> AQI 114 优</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-box" id="sub-info"></div>
|
||||
<div class="info-box" id="hours-info"></div>
|
||||
<div class="info-box" id="days-info"></div>
|
||||
|
||||
<script src="./js/card.js"></script>
|
||||
<script src="./js/weather_now.js"></script>
|
||||
</body>
|
@ -12,6 +12,7 @@ from pydantic import BaseModel
|
||||
class LiteModel(BaseModel):
|
||||
TABLE_NAME: str = None
|
||||
id: int = None
|
||||
|
||||
def dump(self, *args, **kwargs):
|
||||
if pydantic.__version__ < "1.8.2":
|
||||
return self.dict(*args, **kwargs)
|
||||
|
@ -6,10 +6,13 @@ import aiofiles
|
||||
import nonebot
|
||||
from nonebot import require
|
||||
|
||||
from liteyuki.utils.base.resource import load_resources
|
||||
|
||||
require("nonebot_plugin_htmlrender")
|
||||
|
||||
from nonebot_plugin_htmlrender import *
|
||||
|
||||
|
||||
async def template2html(
|
||||
template: str,
|
||||
templates: dict,
|
||||
@ -56,9 +59,11 @@ async def template2image(
|
||||
}
|
||||
template_path = os.path.dirname(template)
|
||||
template_name = os.path.basename(template)
|
||||
print(template_path, template_name)
|
||||
|
||||
if debug:
|
||||
# 重载资源
|
||||
load_resources()
|
||||
|
||||
raw_html = await template_to_html(
|
||||
template_name=template_name,
|
||||
template_path=template_path,
|
||||
|
@ -3,6 +3,7 @@ aiofiles==23.2.1
|
||||
colored==2.2.4
|
||||
dash==2.16.1
|
||||
GitPython==3.1.42
|
||||
httpx==0.27.0
|
||||
jieba==0.42.1
|
||||
nb-cli==1.4.1
|
||||
nonebot2[fastapi,httpx,websockets]==2.2.1
|
||||
|