Code Rebase - 1.0.0 by itzdrli

This commit is contained in:
Letian Li 2025-05-03 16:24:53 +02:00
parent 50cba9e6be
commit db1a9e33e6
6 changed files with 84 additions and 53 deletions

View File

@ -1,6 +0,0 @@
pull_request_title: 'i18n: update translations'
pull_request_labels:
- i18n
files:
- source: /src/locales/zh-CN.yml
translation: /src/locales/%locale%.yml

View File

@ -1,25 +1,25 @@
{ {
"name": "koishi-plugin-market-info", "name": "koishi-plugin-market-info-plus",
"description": "Koishi plugin market information", "description": "Koishi plugin market information",
"version": "2.1.0", "version": "1.0.0",
"main": "lib/index.js", "main": "lib/index.js",
"typings": "lib/index.d.ts", "typings": "lib/index.d.ts",
"files": [ "files": [
"lib", "lib",
"dist" "dist"
], ],
"author": "Shigma <shigma10826@gmail.com>", "author": "itzdrli <itzdrli@proton.me>",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/koishijs/koishi-plugin-market-info.git" "url": "git+https://github.com/itzdrli/koishi-plugin-market-info-plus.git"
}, },
"bugs": { "bugs": {
"url": "https://github.com/koishijs/koishi-plugin-market-info/issues" "url": "https://github.com/itzdrli/koishi-plugin-market-info-plus/issues"
}, },
"homepage": "https://github.com/koishijs/koishi-plugin-market-info#readme", "homepage": "https://github.com/itzdrli/koishi-plugin-market-info-plus#readme",
"scripts": { "scripts": {
"build": "atsc -b" "build": "yakumo build"
}, },
"koishi": { "koishi": {
"description": { "description": {
@ -39,13 +39,14 @@
"manager" "manager"
], ],
"peerDependencies": { "peerDependencies": {
"koishi": "^4.15.0" "koishi": "^4.17.0"
}, },
"devDependencies": { "devDependencies": {
"@koishijs/registry": "^6.0.4", "@koishijs/registry": "^6.0.4",
"@types/node": "^20.8.10", "@types/node": "^20.8.10",
"atsc": "^1.2.2", "atsc": "^1.2.2",
"koishi": "^4.15.0", "koishi": "^4.15.0",
"koishi-plugin-puppeteer": "^3.9.0",
"typescript": "^5.2.2" "typescript": "^5.2.2"
} }
} }

View File

@ -1,8 +1,10 @@
import { Context, Dict, Schema, Time, deepEqual, pick, sleep } from 'koishi' import { Context, Dict, Schema, Time, deepEqual, pick, sleep } from 'koishi'
import {} from '@koishijs/plugin-market' import {} from '@koishijs/plugin-market'
import type { SearchObject, SearchResult } from '@koishijs/registry' import type { SearchObject, SearchResult } from '@koishijs/registry'
import { } from 'koishi-plugin-puppeteer'
import { renderMarketUpdate } from './renderImage'
export const name = 'market-info' export const name = 'market-info-plus'
interface Receiver { interface Receiver {
platform: string platform: string
@ -11,6 +13,8 @@ interface Receiver {
guildId?: string guildId?: string
} }
export const inject = ["puppeteer"]
const Receiver: Schema<Receiver> = Schema.object({ const Receiver: Schema<Receiver> = Schema.object({
platform: Schema.string().required().description('平台名称。'), platform: Schema.string().required().description('平台名称。'),
selfId: Schema.string().required().description('机器人 ID。'), selfId: Schema.string().required().description('机器人 ID。'),
@ -30,7 +34,7 @@ export interface Config {
export const Config: Schema<Config> = Schema.object({ export const Config: Schema<Config> = Schema.object({
rules: Schema.array(Receiver).role('table').description('推送规则列表。'), rules: Schema.array(Receiver).role('table').description('推送规则列表。'),
endpoint: Schema.string().default('https://registry.koishi.chat/index.json').description('插件市场地址。'), endpoint: Schema.string().default('https://kp.itzdrli.cc').description('插件市场地址。'),
interval: Schema.number().default(Time.minute * 30).description('轮询间隔 (毫秒)。'), interval: Schema.number().default(Time.minute * 30).description('轮询间隔 (毫秒)。'),
showHidden: Schema.boolean().default(false).description('是否显示隐藏的插件。'), showHidden: Schema.boolean().default(false).description('是否显示隐藏的插件。'),
showDeletion: Schema.boolean().default(false).description('是否显示删除的插件。'), showDeletion: Schema.boolean().default(false).description('是否显示删除的插件。'),
@ -39,9 +43,7 @@ export const Config: Schema<Config> = Schema.object({
}) })
export function apply(ctx: Context, config: Config) { export function apply(ctx: Context, config: Config) {
ctx.i18n.define('zh', require('./locales/zh-CN')) const logger = ctx.logger('market-info-plus')
const logger = ctx.logger('market')
const makeDict = (result: SearchResult) => { const makeDict = (result: SearchResult) => {
const dict: Dict<SearchObject> = {} const dict: Dict<SearchObject> = {}
@ -72,24 +74,25 @@ export function apply(ctx: Context, config: Config) {
) )
}) })
if (options.receive) { if (options.receive) {
if (index >= 0) return session.text('.not-modified') if (index >= 0) return `未修改订阅信息。`
config.rules.push(pick(session, ['platform', 'selfId', 'channelId', 'guildId'])) config.rules.push(pick(session, ['platform', 'selfId', 'channelId', 'guildId']))
} else { } else {
if (index < 0) return session.text('.not-modified') if (index < 0) return `未修改订阅信息。`
config.rules.splice(index, 1) config.rules.splice(index, 1)
} }
ctx.scope.update(config, false) ctx.scope.update(config, false)
return session.text('.updated') return `已更新订阅信息。`
} }
if (!name) { if (!name) {
const objects = Object.values(previous).filter(data => !data.manifest.hidden) const objects = Object.values(previous).filter(data => !data.manifest.hidden)
return session.text('.overview', [objects.length]) return `当前共有 ${objects.length} 个插件`
} }
const data = previous[name] const data = previous[name]
if (!data) return session.text('.not-found', [name]) if (!data) `未找到插件 ${name}`
return session.text('.detail', data) return `${data.shortname} (${data.package.version})\n\n` +
`发布者:@${data.package.publisher.username}`
}) })
ctx.setInterval(async () => { ctx.setInterval(async () => {
@ -97,10 +100,12 @@ export function apply(ctx: Context, config: Config) {
const diff = Object.keys({ ...previous, ...current }).map((name) => { const diff = Object.keys({ ...previous, ...current }).map((name) => {
const version1 = previous[name]?.package.version const version1 = previous[name]?.package.version
const version2 = current[name]?.package.version const version2 = current[name]?.package.version
if (version1 === version2) return if (version1 === version2) {
return
}
if (!version1) { if (!version1) {
let output = <p><i18n path="market-info.created"></i18n></p> let output = `新增:${name} (${version2})`
if (config.showPublisher) output += ` (@${current[name].package.publisher.username})` if (config.showPublisher) output += ` (@${current[name].package.publisher.username})`
if (config.showDescription) { if (config.showDescription) {
const { description } = current[name].manifest const { description } = current[name].manifest
@ -126,12 +131,18 @@ export function apply(ctx: Context, config: Config) {
const content = ['[插件市场更新]', ...diff].join('\n') const content = ['[插件市场更新]', ...diff].join('\n')
logger.info(content) logger.info(content)
// Generate image
const image = await renderMarketUpdate(ctx, config, diff, previous)
const delay = ctx.root.config.delay.broadcast const delay = ctx.root.config.delay.broadcast
for (let index = 0; index < config.rules.length; ++index) { for (let index = 0; index < config.rules.length; ++index) {
if (index && delay) await sleep(delay) if (index && delay) await sleep(delay)
const { platform, selfId, channelId, guildId } = config.rules[index] const { platform, selfId, channelId, guildId } = config.rules[index]
const bot = ctx.bots.find(bot => bot.platform === platform && bot.selfId === selfId) const bot = ctx.bots.find(bot => bot.platform === platform && bot.selfId === selfId)
bot.sendMessage(channelId, content, guildId) // Send both text and image
await bot.sendMessage(channelId, content, guildId)
await bot.sendMessage(channelId, image, guildId)
} }
}, config.interval) }, config.interval)
}) })

View File

@ -1,21 +0,0 @@
commands:
market:
description: 插件市场信息
messages:
overview: 当前共有 {0} 个插件。
not-found: 未找到插件 {0}。
updated: 已更新订阅信息。
not-modified: 未修改订阅信息。
detail: |-
{name} ({version})
{manifest.description.zh || manifest.description.en}
options:
receive.true: 订阅到此频道
receive.false: 取消订阅到此频道
market-info:
header: '[插件市场更新]'
created: 新增:{0}
updated: 更新:{0} ({1} → {2})`
deleted: 移除:{0}

40
src/renderImage.ts Normal file
View File

@ -0,0 +1,40 @@
import { Context } from 'koishi'
import { Config } from './index'
// Dark theme colors
const dark = ['#2e3440', '#ffffff', '#434c5e']
export async function renderMarketUpdate(ctx: Context, config: Config, diff: string[], previous: any) {
const cardHtml = diff.map(item => {
return `
<div class="col-4 flex flex-col h-full w-full min-w-[250px] max-w-[350px]">
<div class="bg-[${dark[2]}] shadow-lg rounded-2xl p-4 flex flex-col justify-between h-full">
<h2 class="text-lg font-semibold mb-2 flex-grow break-words text-[${dark[1]}]">${item}</h2>
</div>
</div>
`
}).join('')
const html = `
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-[${dark[0]}] text-[${dark[1]}]">
<div class="max-w-7xl mx-auto p-4">
<div class="text-center mb-5">
<div class="bg-[${dark[2]}] shadow-lg rounded-2xl py-4 px-6">
<p class="text-2xl font-bold text-[${dark[1]}]">[]</p>
</div>
</div>
<div class="grid grid-cols-4 gap-3">
${cardHtml}
</div>
</div>
</body>
`
return await ctx.puppeteer.render(html)
}

View File

@ -2,16 +2,22 @@
"compilerOptions": { "compilerOptions": {
"rootDir": "src", "rootDir": "src",
"outDir": "lib", "outDir": "lib",
"target": "es2020", "target": "es2022",
"module": "commonjs", "module": "esnext",
"emitDeclarationOnly": true,
"declaration": true, "declaration": true,
"composite": true, "composite": true,
"incremental": true, "incremental": true,
"skipLibCheck": true, "skipLibCheck": true,
"esModuleInterop": true, "esModuleInterop": true,
"moduleResolution": "node", "moduleResolution": "bundler",
"jsx": "react-jsx", "jsx": "react-jsx",
"resolveJsonModule": true,
"jsxImportSource": "@satorijs/element", "jsxImportSource": "@satorijs/element",
"types": [
"node",
"yml-register/types"
]
}, },
"include": [ "include": [
"src" "src"