diff --git a/package.json b/package.json index 16dde59..cd8ce52 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "koishi-plugin-memes-api", "description": "表情包制作插件调用 API 版", - "version": "0.1.11", + "version": "0.1.12", "main": "lib/index.js", "typings": "lib/index.d.ts", "files": [ diff --git a/readme.md b/readme.md index c3c7701..9fa3e50 100644 --- a/readme.md +++ b/readme.md @@ -82,6 +82,10 @@ Telegram:[@lgc2333](https://t.me/lgc2333) ## 📝 更新日志 +### 0.1.12 + +- [#7](https://github.com/lgc2333/koishi-plugin-memes-api/issues/7) + ### 0.1.11 - fix [#6](https://github.com/lgc2333/koishi-plugin-memes-api/issues/6) `meme ls 的时候会让 gocq 出现无法发图片的情况` diff --git a/src/config.ts b/src/config.ts index 8ac1352..d282b5d 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,28 +1,70 @@ import { Quester, Schema } from 'koishi'; import { configLocale } from './locale'; -export interface Config { +interface ICommandConfig { enableShortcut: boolean; + silentShortcut?: boolean; + moreSilent?: boolean; +} + +interface ICacheConfig { cacheDir: string; keepCache: boolean; +} + +interface IRequestConfig { requestConfig: Quester.Config; } -export const Config: Schema = Schema.intersect([ - Schema.object({ - enableShortcut: Schema.boolean() - .default(true) - .description(configLocale.command.enableShortcut), - }).description(configLocale.command.title), - Schema.object({ - cacheDir: Schema.path({ filters: ['directory'], allowCreate: true }) - .default('cache/memes') - .description(configLocale.cache.cacheDir), - keepCache: Schema.boolean() - .default(false) - .description(configLocale.cache.keepCache), - }).description(configLocale.cache.title), - Schema.object({ - requestConfig: Quester.createConfig('http://127.0.0.1:2233'), - }), +export type IConfig = ICommandConfig & ICacheConfig & IRequestConfig; + +const baseCmdCfg = Schema.object({ + enableShortcut: Schema.boolean() + .default(true) + .description(configLocale.command.enableShortcut), +}).description(configLocale.command.title); +const cmdCfgWithSilent = Schema.intersect([ + baseCmdCfg, + Schema.union([ + Schema.object({ + enableShortcut: Schema.const(true), + silentShortcut: Schema.boolean() + .default(false) + .description(configLocale.command.silentShortcut), + }), + Schema.object({}), + ]), +]); +const cmdCfgWithMoreSilent = Schema.intersect([ + cmdCfgWithSilent, + Schema.union([ + Schema.object({ + enableShortcut: Schema.const(true), + silentShortcut: Schema.const(true).required(), + moreSilent: Schema.boolean() + .default(false) + .description(configLocale.command.moreSilent), + }), + Schema.object({}), + ]), +]); +const commandConfig: Schema = cmdCfgWithMoreSilent; + +const cacheConfig: Schema = Schema.object({ + cacheDir: Schema.path({ filters: ['directory'], allowCreate: true }) + .default('cache/memes') + .description(configLocale.cache.cacheDir), + keepCache: Schema.boolean() + .default(false) + .description(configLocale.cache.keepCache), +}).description(configLocale.cache.title); + +const requestConfig: Schema = Schema.object({ + requestConfig: Quester.createConfig('http://127.0.0.1:2233'), +}); + +export const Config: Schema = Schema.intersect([ + commandConfig, + cacheConfig, + requestConfig, ]); diff --git a/src/data-source.ts b/src/data-source.ts index 1693c3b..d27eac8 100644 --- a/src/data-source.ts +++ b/src/data-source.ts @@ -5,7 +5,7 @@ import { Quester, h } from 'koishi'; import path from 'path'; import { AxiosRequestConfig, AxiosResponse } from 'axios'; -import { Config } from './config'; +import { IConfig } from './config'; import { logger } from './const'; import { MemeError } from './error'; @@ -105,7 +105,7 @@ export class MemeSource { protected previewCacheJsonPath: string; - constructor(protected config: Config, protected http: Quester) { + constructor(protected config: IConfig, protected http: Quester) { this.previewCacheJsonPath = path.join( this.config.cacheDir, `preview_path.json` diff --git a/src/error.ts b/src/error.ts index 58f99ff..da09826 100644 --- a/src/error.ts +++ b/src/error.ts @@ -5,49 +5,59 @@ import type { AxiosResponse } from 'axios'; import type { MemeParams } from './data-source'; import { formatRange } from './utils'; -export type RequestErrorTypes = - | 'no-such-meme' - | 'text-over-length' - | 'open-image-failed' - | 'parser-exit' - | 'image-number-mismatch' - | 'text-number-mismatch' - | 'text-or-name-not-enough' - | 'arg-parser-exit' - | 'arg-model-mismatch' - | 'arg-mismatch' - | 'param-mismatch' - | 'unknown-error' - | 'unexpected-error'; - -export type OtherErrorTypes = - | 'text-or-name-not-enough' - | 'platform-not-supported' - | 'download-avatar-failed' - | 'no-such-index'; - +export const requestErrorTypes = [ + 'no-such-meme', + 'text-over-length', + 'open-image-failed', + 'parser-exit', + 'image-number-mismatch', + 'text-number-mismatch', + 'text-or-name-not-enough', + 'arg-parser-exit', + 'arg-model-mismatch', + 'arg-mismatch', + 'param-mismatch', + 'unknown-error', + 'unexpected-error', +] as const; +export const otherErrorTypes = [ + 'text-or-name-not-enough', + 'platform-not-supported', + 'download-avatar-failed', + 'no-such-index', +] as const; + +export type RequestErrorTypes = (typeof requestErrorTypes)[number]; +export type OtherErrorTypes = (typeof otherErrorTypes)[number]; export type ErrorTypes = RequestErrorTypes | OtherErrorTypes; +export const paramErrorTypes: readonly ErrorTypes[] = [ + 'image-number-mismatch', + 'text-number-mismatch', + 'text-or-name-not-enough', + 'arg-parser-exit', + 'arg-model-mismatch', + 'arg-mismatch', + 'param-mismatch', +] as const; + +export const errorCodeMap: Record = { + 531: 'no-such-meme', + 532: 'text-over-length', + 533: 'open-image-failed', + 534: 'parser-exit', + 541: 'image-number-mismatch', + 542: 'text-number-mismatch', + 543: 'text-or-name-not-enough', + 551: 'arg-parser-exit', + 552: 'arg-model-mismatch', +}; + export function getErrorType(errorCode?: number): RequestErrorTypes { if (!errorCode) return 'unexpected-error'; - - const errorTypes: Record = { - 531: 'no-such-meme', - 532: 'text-over-length', - 533: 'open-image-failed', - 534: 'parser-exit', - 541: 'image-number-mismatch', - 542: 'text-number-mismatch', - 543: 'text-or-name-not-enough', - 551: 'arg-parser-exit', - 552: 'arg-model-mismatch', - }; - - if (errorCode in errorTypes) return errorTypes[errorCode]; - + if (errorCode in errorCodeMap) return errorCodeMap[errorCode]; if (errorCode >= 550 && errorCode < 560) return 'arg-mismatch'; if (errorCode >= 540 && errorCode < 550) return 'param-mismatch'; - return 'unknown-error'; } diff --git a/src/index.ts b/src/index.ts index 5f3fe8e..8ea57c5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import { Context, Session, escapeRegExp, h } from 'koishi'; -import { Config } from './config'; +import { Config, IConfig } from './config'; import { logger } from './const'; import { MemeSource, @@ -8,12 +8,13 @@ import { getRetFileByResp, returnFileToElem, } from './data-source'; -import { MemeError, formatError } from './error'; +import { MemeError, formatError, paramErrorTypes } from './error'; import { locale } from './locale'; import { extractPlaintext, formatRange, getAvatarUrlFromID, + getI18N, splitArg, } from './utils'; @@ -42,7 +43,8 @@ function wrapError( }; } -export async function apply(ctx: Context, config: Config) { +export async function apply(ctx: Context, config: IConfig) { + ctx.i18n.define('zh-CN', locale as any); ctx.i18n.define('zh', locale as any); const http = ctx.http.extend(config.requestConfig); @@ -303,17 +305,37 @@ export async function apply(ctx: Context, config: Config) { const content = extractPlaintext(session.elements).trim(); + const generate = async ( + ...rest: Parameters + ): Promise => { + const rh = await generateMeme(...rest); + if (rh?.type !== 'i18n') return rh; + + const errPfx = 'memes-api.errors.'; + const i18nPath = rh.attrs.path as string; + const i18nArgs = rh.children as any[]; + if (i18nPath && i18nPath.startsWith(errPfx)) { + const errType = i18nPath.slice(errPfx.length); + if ( + config.silentShortcut && + (config.moreSilent || paramErrorTypes.includes(errType as any)) + ) { + logger.warn(`Silenced error: ${getI18N(ctx, i18nPath, i18nArgs)}`); + return undefined; + } + } + return rh; + }; + for (const match of matches) { const { key, prefixes, patterns } = match; for (const pfx of prefixes) { - if (content.startsWith(pfx)) return generateMeme(session, key, pfx); + if (content.startsWith(pfx)) return generate(session, key, pfx); } for (const ptn of patterns) { const ptnMatch = content.match(ptn); - if (ptnMatch) { - return generateMeme(session, key, '', ptnMatch.slice(2)); - } + if (ptnMatch) return generate(session, key, '', ptnMatch.slice(2)); } } diff --git a/src/locale.ts b/src/locale.ts index 8da2460..d975777 100644 --- a/src/locale.ts +++ b/src/locale.ts @@ -48,6 +48,8 @@ export interface ConfigLocaleBase { export interface MemeCommandConfigLocale extends ConfigLocaleBase { enableShortcut: string; + silentShortcut: string; + moreSilent: string; } export interface MemeCacheConfigLocale extends ConfigLocaleBase { diff --git a/src/locales/zh-CN.yml b/src/locales/zh-CN.yml index 7943e88..2b0eb49 100644 --- a/src/locales/zh-CN.yml +++ b/src/locales/zh-CN.yml @@ -64,6 +64,8 @@ memes-api: enableShortcut: |- 是否注册类似原版 `memes` 插件的触发指令。 例:`meme generate 5000兆 我去 洛天依` -> `5000兆 我去 洛天依` + silentShortcut: 是否禁用使用原版触发指令时的 参数错误提示。 + moreSilent: 是否禁用使用原版触发指令时的 **所有** 错误提示。 cache: title: 缓存设置 cacheDir: 插件图片缓存存放的目录。