koishi-plugin-chatsound 0.0.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -1,10 +1,20 @@
1
1
  import { Context, Schema } from 'koishi';
2
+ import SilkService from 'koishi-plugin-silk';
3
+ declare module 'koishi' {
4
+ interface Context {
5
+ silk: SilkService;
6
+ }
7
+ }
2
8
  export declare const name = "chatsound";
9
+ export declare const inject: {
10
+ optional: string[];
11
+ };
3
12
  export interface Config {
4
13
  soundPath: string[];
5
14
  defaultPitch: number;
6
15
  minPitch: number;
7
16
  maxPitch: number;
17
+ audioType: "mp3" | "silk";
8
18
  }
9
19
  export declare const Config: Schema<Config>;
10
20
  export declare function apply(ctx: Context, config: Config): void;
package/lib/index.js CHANGED
@@ -22,6 +22,7 @@ var src_exports = {};
22
22
  __export(src_exports, {
23
23
  Config: () => Config,
24
24
  apply: () => apply,
25
+ inject: () => inject,
25
26
  name: () => name
26
27
  });
27
28
  module.exports = __toCommonJS(src_exports);
@@ -29,14 +30,16 @@ var import_koishi = require("koishi");
29
30
  var import_promises = require("fs/promises");
30
31
  var import_path = require("path");
31
32
  var import_child_process = require("child_process");
32
- var import_util = require("util");
33
- var execAsync = (0, import_util.promisify)(import_child_process.exec);
34
33
  var name = "chatsound";
34
+ var inject = {
35
+ optional: ["silk"]
36
+ };
35
37
  var Config = import_koishi.Schema.object({
36
- soundPath: import_koishi.Schema.array(import_koishi.Schema.string()).description("用于搜索的音频路径"),
38
+ soundPath: import_koishi.Schema.array(import_koishi.Schema.string()).description("用于搜索音频的*绝对*路径,支持搜索mp3 wav ogg flac m4a aac格式"),
37
39
  defaultPitch: import_koishi.Schema.number().default(100).description("默认的语音音调(百分比)"),
38
40
  minPitch: import_koishi.Schema.number().default(80).min(0).description("最小Pitch,不小于0"),
39
- maxPitch: import_koishi.Schema.number().default(200).description("最大Pitch")
41
+ maxPitch: import_koishi.Schema.number().default(200).description("最大Pitch"),
42
+ audioType: import_koishi.Schema.union(["mp3", "silk"]).default("mp3").description("最终发送的类型,QQ及微信选择SILK")
40
43
  });
41
44
  var AUDIO_EXTENSIONS = [".mp3", ".wav", ".ogg", ".flac", ".m4a", ".aac"];
42
45
  async function findAudioFile(trigger, soundPaths) {
@@ -59,11 +62,61 @@ async function findAudioFile(trigger, soundPaths) {
59
62
  return null;
60
63
  }
61
64
  __name(findAudioFile, "findAudioFile");
62
- async function applyPitch(inputPath, pitch) {
65
+ async function runFFmpeg(commandArgs) {
66
+ return new Promise((resolve, reject) => {
67
+ const ffmpeg = (0, import_child_process.spawn)("ffmpeg", commandArgs);
68
+ const chunks = [];
69
+ ffmpeg.stdout.on("data", (chunk) => chunks.push(chunk));
70
+ ffmpeg.on("close", (code) => {
71
+ if (code === 0) {
72
+ resolve(Buffer.concat(chunks));
73
+ } else {
74
+ reject(new Error(`FFmpeg exited with code ${code}`));
75
+ }
76
+ });
77
+ ffmpeg.on("error", reject);
78
+ });
79
+ }
80
+ __name(runFFmpeg, "runFFmpeg");
81
+ async function applyPitch(inputPath, pitch, audioType) {
63
82
  const pitchFactor = pitch / 100;
64
- const command = `ffmpeg -i "${inputPath}" -filter:a "asetrate=44100*${pitchFactor},aresample=44100" -f mp3 -`;
65
- const { stdout } = await execAsync(command);
66
- return Buffer.from(stdout);
83
+ if (audioType === "mp3") {
84
+ const args = [
85
+ "-i",
86
+ inputPath,
87
+ "-vn",
88
+ "-sn",
89
+ "-dn",
90
+ "-filter:a",
91
+ `rubberband=pitch=${pitchFactor}`,
92
+ "-f",
93
+ "mp3",
94
+ "-y",
95
+ "pipe:1"
96
+ ];
97
+ const data = await runFFmpeg(args);
98
+ return { data, mimeType: "audio/mp3" };
99
+ } else {
100
+ const args = [
101
+ "-i",
102
+ inputPath,
103
+ "-vn",
104
+ "-sn",
105
+ "-dn",
106
+ "-filter:a",
107
+ `rubberband=pitch=${pitchFactor}`,
108
+ "-f",
109
+ "s16le",
110
+ "-ac",
111
+ "1",
112
+ "-ar",
113
+ "24000",
114
+ "-y",
115
+ "pipe:1"
116
+ ];
117
+ const data = await runFFmpeg(args);
118
+ return { data, mimeType: "audio/pcm" };
119
+ }
67
120
  }
68
121
  __name(applyPitch, "applyPitch");
69
122
  function apply(ctx, config) {
@@ -77,8 +130,17 @@ function apply(ctx, config) {
77
130
  return `没有这种音频`;
78
131
  }
79
132
  try {
80
- const audioBuffer = await applyPitch(audioPath, actualPitch);
81
- await session.send(import_koishi.h.audio(audioBuffer, "audio/mp3"));
133
+ const { data, mimeType } = await applyPitch(audioPath, actualPitch, config.audioType);
134
+ if (config.audioType === "silk") {
135
+ if (ctx.silk) {
136
+ const silkResult = await ctx.silk.encode(data, 24e3);
137
+ await session.send(import_koishi.h.audio(silkResult.data, "audio/silk"));
138
+ } else {
139
+ return "没有安装必要的SILK插件";
140
+ }
141
+ } else {
142
+ await session.send(import_koishi.h.audio(data, mimeType));
143
+ }
82
144
  } catch (error) {
83
145
  ctx.logger.error("发送音频失败:", error);
84
146
  return "发送音频失败";
@@ -90,5 +152,6 @@ __name(apply, "apply");
90
152
  0 && (module.exports = {
91
153
  Config,
92
154
  apply,
155
+ inject,
93
156
  name
94
157
  });
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "contributors": [
5
5
  "Dr.Abc <me@drabc.net>"
6
6
  ],
7
- "version": "0.0.2",
7
+ "version": "1.0.0",
8
8
  "homepage": "https://github.com/DrAbcOfficial/koishi-plugin-chatsound",
9
9
  "repository": {
10
10
  "type": "git",
@@ -13,7 +13,8 @@
13
13
  "main": "lib/index.js",
14
14
  "typings": "lib/index.d.ts",
15
15
  "files": [
16
- "lib"
16
+ "lib",
17
+ "dist"
17
18
  ],
18
19
  "license": "MIT",
19
20
  "scripts": {},
@@ -31,6 +32,9 @@
31
32
  "en": "发送预定的噪音,可以变调,依赖ffmpeg",
32
33
  "zh": "发送预定的噪音,可以变调,依赖ffmpeg"
33
34
  },
35
+ "service":{
36
+ "optional": ["silk"]
37
+ },
34
38
  "preview": true
35
39
  }
36
40
  }