Skip to content

Commit

Permalink
up
Browse files Browse the repository at this point in the history
  • Loading branch information
lgc2333 committed Oct 9, 2023
1 parent d8fce41 commit 1fcbf86
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 65 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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": [
Expand Down
4 changes: 4 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 出现无法发图片的情况`
Expand Down
78 changes: 60 additions & 18 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -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<Config> = 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<ICommandConfig> = cmdCfgWithMoreSilent;

const cacheConfig: Schema<ICacheConfig> = 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<IRequestConfig> = Schema.object({
requestConfig: Quester.createConfig('http://127.0.0.1:2233'),
});

export const Config: Schema<IConfig> = Schema.intersect([
commandConfig,
cacheConfig,
requestConfig,
]);
4 changes: 2 additions & 2 deletions src/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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`
Expand Down
84 changes: 47 additions & 37 deletions src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<number, RequestErrorTypes> = {
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<number, RequestErrorTypes> = {
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';
}

Expand Down
36 changes: 29 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { Context, Session, escapeRegExp, h } from 'koishi';

import { Config } from './config';
import { Config, IConfig } from './config';
import { logger } from './const';
import {
MemeSource,
ReturnFile,
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';

Expand Down Expand Up @@ -42,7 +43,8 @@ function wrapError<TA extends any[], TR>(
};
}

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);
Expand Down Expand Up @@ -303,17 +305,37 @@ export async function apply(ctx: Context, config: Config) {

const content = extractPlaintext(session.elements).trim();

const generate = async (
...rest: Parameters<typeof generateMeme>
): Promise<h | undefined> => {
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));
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export interface ConfigLocaleBase {

export interface MemeCommandConfigLocale extends ConfigLocaleBase {
enableShortcut: string;
silentShortcut: string;
moreSilent: string;
}

export interface MemeCacheConfigLocale extends ConfigLocaleBase {
Expand Down
2 changes: 2 additions & 0 deletions src/locales/zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ memes-api:
enableShortcut: |-
是否注册类似原版 `memes` 插件的触发指令。
例:`meme generate 5000兆 我去 洛天依` -> `5000兆 我去 洛天依`
silentShortcut: 是否禁用使用原版触发指令时的 参数错误提示。
moreSilent: 是否禁用使用原版触发指令时的 **所有** 错误提示。
cache:
title: 缓存设置
cacheDir: 插件图片缓存存放的目录。
Expand Down

0 comments on commit 1fcbf86

Please sign in to comment.