forked from bot/app
✨ Add sign status for Lagrange.Core
This commit is contained in:
parent
75a4d1fdcb
commit
205b69e5cb
4
.gitignore
vendored
4
.gitignore
vendored
@ -15,7 +15,6 @@ _config.yml
|
|||||||
config.yml
|
config.yml
|
||||||
config.example.yml
|
config.example.yml
|
||||||
compile.bat
|
compile.bat
|
||||||
.cache/
|
|
||||||
liteyuki/resources/templates/latest-debug.html
|
liteyuki/resources/templates/latest-debug.html
|
||||||
# vuepress
|
# vuepress
|
||||||
.github
|
.github
|
||||||
@ -33,3 +32,6 @@ docs/.vuepress/.cache/
|
|||||||
docs/.vuepress/.temp/
|
docs/.vuepress/.temp/
|
||||||
docs/.vuepress/dist/
|
docs/.vuepress/dist/
|
||||||
prompt.txt
|
prompt.txt
|
||||||
|
|
||||||
|
# js
|
||||||
|
**/echarts.js
|
@ -1,5 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
import httpx
|
import httpx
|
||||||
import nonebot
|
import nonebot
|
||||||
from nonebot import require
|
from nonebot import require
|
||||||
@ -33,9 +34,9 @@ async def request_for_blacklist():
|
|||||||
for plat in platforms:
|
for plat in platforms:
|
||||||
for url in urls:
|
for url in urls:
|
||||||
url += f"{plat}.txt"
|
url += f"{plat}.txt"
|
||||||
async with httpx.AsyncClient() as client:
|
async with aiohttp.ClientSession() as client:
|
||||||
resp = await client.get(url)
|
resp = await client.get(url)
|
||||||
blacklist_data[plat] = set(resp.text.splitlines())
|
blacklist_data[plat] = set((await resp.text()).splitlines())
|
||||||
blacklist = get_uni_set()
|
blacklist = get_uni_set()
|
||||||
nonebot.logger.info("blacklists updated")
|
nonebot.logger.info("blacklists updated")
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import aiohttp
|
||||||
|
|
||||||
from .qw_models import *
|
from .qw_models import *
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
@ -27,7 +29,7 @@ async def check_key_dev(key: str) -> bool:
|
|||||||
}
|
}
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
resp = await client.get(url, params=params)
|
resp = await client.get(url, params=params)
|
||||||
return resp.json().get("code") != "200" # 查询不到付费数据为开发版
|
return (resp.json()).get("code") != "200" # 查询不到付费数据为开发版
|
||||||
|
|
||||||
|
|
||||||
def get_local_data(ulang_code: str) -> dict:
|
def get_local_data(ulang_code: str) -> dict:
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import json
|
|
||||||
import time
|
import time
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
import httpx
|
import aiohttp
|
||||||
from nonebot import require
|
from nonebot import require
|
||||||
from nonebot.plugin import PluginMetadata
|
from nonebot.plugin import PluginMetadata
|
||||||
|
|
||||||
from liteyuki.utils.base.config import get_config
|
from liteyuki.utils.base.config import get_config
|
||||||
from liteyuki.utils.base.data import Database, LiteModel
|
from liteyuki.utils.base.data import Database, LiteModel
|
||||||
|
from liteyuki.utils.base.resource import get_path
|
||||||
|
from liteyuki.utils.message.html_tool import template2image
|
||||||
|
|
||||||
require("nonebot_plugin_alconna")
|
require("nonebot_plugin_alconna")
|
||||||
require("nonebot_plugin_apscheduler")
|
require("nonebot_plugin_apscheduler")
|
||||||
from nonebot_plugin_apscheduler import scheduler
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
from nonebot_plugin_alconna import Alconna, Subcommand, on_alconna
|
from nonebot_plugin_alconna import Alconna, AlconnaResult, CommandResult, Subcommand, UniMessage, on_alconna, Args
|
||||||
|
|
||||||
__author__ = "snowykami"
|
__author__ = "snowykami"
|
||||||
__plugin_meta__ = PluginMetadata(
|
__plugin_meta__ = PluginMetadata(
|
||||||
@ -46,7 +46,8 @@ sign_db.auto_migrate(SignCount())
|
|||||||
sign_status = on_alconna(Alconna(
|
sign_status = on_alconna(Alconna(
|
||||||
"sign",
|
"sign",
|
||||||
Subcommand(
|
Subcommand(
|
||||||
"chart"
|
"chart",
|
||||||
|
Args["limit", int, 60]
|
||||||
),
|
),
|
||||||
Subcommand(
|
Subcommand(
|
||||||
"count"
|
"count"
|
||||||
@ -83,8 +84,10 @@ async def _():
|
|||||||
|
|
||||||
|
|
||||||
@sign_status.assign("chart")
|
@sign_status.assign("chart")
|
||||||
async def _():
|
async def _(arp: CommandResult = AlconnaResult()):
|
||||||
pass
|
limit = arp.result.main_args.get("limit", 60)
|
||||||
|
img = await generate_chart(limit)
|
||||||
|
await sign_status.send(UniMessage.image(raw=img))
|
||||||
|
|
||||||
|
|
||||||
@scheduler.scheduled_job("interval", seconds=SIGN_COUNT_DURATION, next_run_time=datetime.datetime.now())
|
@scheduler.scheduled_job("interval", seconds=SIGN_COUNT_DURATION, next_run_time=datetime.datetime.now())
|
||||||
@ -104,10 +107,10 @@ async def get_now_sign() -> dict[str, tuple[float, int]]:
|
|||||||
"""
|
"""
|
||||||
data = {}
|
data = {}
|
||||||
now = time.time()
|
now = time.time()
|
||||||
async with httpx.AsyncClient() as client:
|
async with aiohttp.ClientSession() as client:
|
||||||
for name, url in SIGN_COUNT_URLS.items():
|
for name, url in SIGN_COUNT_URLS.items():
|
||||||
resp = await client.get(url)
|
async with client.get(url) as resp:
|
||||||
count = resp.json()["count"]
|
count = (await resp.json())["count"]
|
||||||
data[name] = (now, count)
|
data[name] = (now, count)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@ -123,5 +126,25 @@ async def save_sign_count(timestamp: float, count: int, sid: str):
|
|||||||
sign_db.save(SignCount(time=timestamp, count=count, sid=sid))
|
sign_db.save(SignCount(time=timestamp, count=count, sid=sid))
|
||||||
|
|
||||||
|
|
||||||
async def generate_chart(duration: int = 60):
|
async def generate_chart(limit):
|
||||||
pass
|
data = []
|
||||||
|
for name, url in SIGN_COUNT_URLS.items():
|
||||||
|
count_rows = sign_db.all(SignCount(), "sid = ? LIMIT ?", url, limit)
|
||||||
|
data.append(
|
||||||
|
{
|
||||||
|
"name" : name,
|
||||||
|
# "data": [[row.time, row.count] for row in count_rows]
|
||||||
|
"times" : [row.time for row in count_rows],
|
||||||
|
"counts": [row.count for row in count_rows]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
img = await template2image(
|
||||||
|
template=get_path("templates/sign_status.html", debug=True),
|
||||||
|
templates={
|
||||||
|
"data": data
|
||||||
|
},
|
||||||
|
debug=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return img
|
||||||
|
3
liteyuki/resources/lagrange_sign/metadata.yml
Normal file
3
liteyuki/resources/lagrange_sign/metadata.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
name: Sign Status
|
||||||
|
description: for Lagrange
|
||||||
|
version: 2024.4.26
|
@ -0,0 +1,4 @@
|
|||||||
|
.sign-chart {
|
||||||
|
height: 400px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
41
liteyuki/resources/lagrange_sign/templates/js/sign_status.js
Normal file
41
liteyuki/resources/lagrange_sign/templates/js/sign_status.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// 数据类型声明
|
||||||
|
// import * as echarts from 'echarts';
|
||||||
|
|
||||||
|
let data = JSON.parse(document.getElementById("data").innerText) // object
|
||||||
|
const signChartDivTemplate = document.importNode(document.getElementById("sign-chart-template").content, true)
|
||||||
|
data.forEach((item) => {
|
||||||
|
let signChartDiv = signChartDivTemplate.cloneNode(true)
|
||||||
|
let chartID = item["name"]
|
||||||
|
// 初始化ECharts实例
|
||||||
|
// 设置id
|
||||||
|
signChartDiv.querySelector(".sign-chart").id = chartID
|
||||||
|
document.body.appendChild(signChartDiv)
|
||||||
|
|
||||||
|
let signChart = echarts.init(document.getElementById(chartID))
|
||||||
|
|
||||||
|
signChart.setOption(
|
||||||
|
{
|
||||||
|
animation: false,
|
||||||
|
title: {
|
||||||
|
text: item["name"],
|
||||||
|
textStyle: {
|
||||||
|
color: '#000000' // 设置标题文本颜色为红色
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: item["times"],
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
min: Math.min(...item["counts"]),
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: item["counts"],
|
||||||
|
type: 'line'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
22
liteyuki/resources/lagrange_sign/templates/sign_status.html
Normal file
22
liteyuki/resources/lagrange_sign/templates/sign_status.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh" xmlns="http://www.w3.org/1999/html">
|
||||||
|
<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/sign_status.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<template id="sign-chart-template">
|
||||||
|
<div class="info-box sign-chart">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="data-storage" id="data">{{ data | tojson }}</div>
|
||||||
|
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
|
||||||
|
<script src="./js/sign_status.js"></script>
|
||||||
|
<script src="./js/card.js"></script>
|
||||||
|
</body>
|
@ -62,6 +62,8 @@ let maxHourlyItem = 8
|
|||||||
let percentWidth = 1 / (maxHourlyItem * 1.5) * 100
|
let percentWidth = 1 / (maxHourlyItem * 1.5) * 100
|
||||||
let hourlyStep = 2 // n小时一个数据
|
let hourlyStep = 2 // n小时一个数据
|
||||||
let hourlyCount = 0
|
let hourlyCount = 0
|
||||||
|
|
||||||
|
let hourlyItemDivTemplate = document.importNode(document.getElementById("hourly-item-template").content, true)
|
||||||
weatherHourly['hourly'].forEach(
|
weatherHourly['hourly'].forEach(
|
||||||
(item, index) => {
|
(item, index) => {
|
||||||
if (index % hourlyStep !== 0) {
|
if (index % hourlyStep !== 0) {
|
||||||
@ -71,7 +73,7 @@ weatherHourly['hourly'].forEach(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let hourlyItemDiv = document.importNode(document.getElementById("hourly-item-template").content, true)
|
let hourlyItemDiv = document.importNode(hourlyItemDivTemplate, true)
|
||||||
hourlyItemDiv.className = "hourly-item"
|
hourlyItemDiv.className = "hourly-item"
|
||||||
hourlyItemDiv.querySelector('.hourly-icon').setAttribute("src", `./img/qw_icon/${item["icon"]}.png`)
|
hourlyItemDiv.querySelector('.hourly-icon').setAttribute("src", `./img/qw_icon/${item["icon"]}.png`)
|
||||||
hourlyItemDiv.querySelector('.hourly-time').innerText = get_time_hour(item["fxTime"])
|
hourlyItemDiv.querySelector('.hourly-time').innerText = get_time_hour(item["fxTime"])
|
||||||
@ -92,6 +94,8 @@ let days = [localData['today'], localData['tomorrow']]
|
|||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
days.push(localData[daysStandard[(todayDay + 2 + i) % 7]])
|
days.push(localData[daysStandard[(todayDay + 2 + i) % 7]])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let dailyItemDivTemplate = document.importNode(document.getElementById("daily-item-template").content, true)
|
||||||
weatherDaily['daily'].forEach(
|
weatherDaily['daily'].forEach(
|
||||||
(item, index) => {
|
(item, index) => {
|
||||||
if (index >= maxDailyItem) {
|
if (index >= maxDailyItem) {
|
||||||
@ -101,7 +105,7 @@ weatherDaily['daily'].forEach(
|
|||||||
if (index >= 2) {
|
if (index >= 2) {
|
||||||
today += `(${item["fxDate"].split("-")[1]}.${item["fxDate"].split("-")[2]})`
|
today += `(${item["fxDate"].split("-")[1]}.${item["fxDate"].split("-")[2]})`
|
||||||
}
|
}
|
||||||
let dailyItemDiv = document.importNode(document.getElementById("daily-item-template").content, true)
|
let dailyItemDiv = document.importNode(dailyItemDivTemplate, true)
|
||||||
dailyItemDiv.querySelector('.icon-day').setAttribute("src", `./img/qw_icon/${item["iconDay"]}.png`)
|
dailyItemDiv.querySelector('.icon-day').setAttribute("src", `./img/qw_icon/${item["iconDay"]}.png`)
|
||||||
dailyItemDiv.querySelector('.icon-night').setAttribute("src", `./img/qw_icon/${item["iconNight"]}.png`)
|
dailyItemDiv.querySelector('.icon-night').setAttribute("src", `./img/qw_icon/${item["iconNight"]}.png`)
|
||||||
|
|
||||||
|
@ -72,5 +72,5 @@
|
|||||||
<div class="info-box" id="days-info"></div>
|
<div class="info-box" id="days-info"></div>
|
||||||
|
|
||||||
<script src="./js/card.js"></script>
|
<script src="./js/card.js"></script>
|
||||||
<script src="js/weather_now.js"></script>
|
<script src="./js/weather_now.js"></script>
|
||||||
</body>
|
</body>
|
@ -1,3 +1,11 @@
|
|||||||
|
:root {
|
||||||
|
--main-text-color: #fff;
|
||||||
|
--sub-text-color: #ccc;
|
||||||
|
--tip-text-color: #999;
|
||||||
|
--device-info-width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.data-storage {
|
.data-storage {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
<div id="motto-text"></div>
|
<div id="motto-text"></div>
|
||||||
<div id="motto-from"></div>
|
<div id="motto-from"></div>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.3.0/echarts.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js"></script>
|
||||||
<script src="./js/motto.js"></script>
|
<script src="./js/motto.js"></script>
|
||||||
<script src="./js/card.js"></script>
|
<script src="./js/card.js"></script>
|
||||||
<script src="./js/status.js"></script>
|
<script src="./js/status.js"></script>
|
||||||
|
Loading…
Reference in New Issue
Block a user