mirror of
https://github.com/chrononeko/chronocat.git
synced 2024-11-22 07:07:53 +00:00
feat(media): implement media engine
This commit is contained in:
parent
9dc0177156
commit
e3bf7cfb95
101
packages/engine-media/src/index.ts
Normal file
101
packages/engine-media/src/index.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import type { ChronocatContext } from '@chronocat/shell'
|
||||
import AdmZip from 'adm-zip'
|
||||
import { execFile } from 'node:child_process'
|
||||
import { BinaryLike, createHash } from 'node:crypto'
|
||||
import { mkdir, unlink, writeFile } from 'node:fs/promises'
|
||||
import { homedir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { arch, platform } from 'node:process'
|
||||
import ntsilkZip from '../../../build/caches/ntsilk.zip'
|
||||
|
||||
declare const __DEFINE_CHRONO_VERSION__: string
|
||||
|
||||
export const name = 'engine-media'
|
||||
export const version = __DEFINE_CHRONO_VERSION__
|
||||
|
||||
const durationRegex = /^ *Duration: (\d+):(\d+):(\d+).(\d+),/m
|
||||
|
||||
export const apply = async (ctx: ChronocatContext) => {
|
||||
let ntsilkPath: string
|
||||
|
||||
try {
|
||||
ntsilkPath = await load(ctx)
|
||||
} catch (cause) {
|
||||
ctx.chronocat.l.warn(
|
||||
new Error('engine-crychiccat: 加载失败', {
|
||||
cause,
|
||||
}),
|
||||
{
|
||||
code: 2162,
|
||||
},
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const register = ctx.chronocat.api.register(name)
|
||||
|
||||
register(
|
||||
'chronocat.internal.media.ntsilk.encode',
|
||||
(payload) =>
|
||||
new Promise((res, rej) => {
|
||||
execFile(
|
||||
ntsilkPath,
|
||||
['-y', '-i', payload.srcPath, '-f', 'ntsilk_s16le', payload.dstPath],
|
||||
{},
|
||||
(err, _stdout, stderr) => {
|
||||
if (err) {
|
||||
// 清理可能存在的已转码文件
|
||||
ctx.chronocat.exists(payload.dstPath).then((x) => {
|
||||
if (x) void unlink(payload.dstPath)
|
||||
})
|
||||
|
||||
rej(err)
|
||||
return
|
||||
}
|
||||
|
||||
const capture = durationRegex.exec(stderr)
|
||||
const hrs = Number(capture?.[1]) || 0
|
||||
const min = Number(capture?.[2]) || 0
|
||||
const sec = Number(capture?.[3]) || 0
|
||||
const ms = Number(capture?.[4]) || 0
|
||||
|
||||
res({
|
||||
duration: 360000 * hrs + 6000 * min + 100 * sec + ms,
|
||||
waveAmplitudes: undefined,
|
||||
})
|
||||
},
|
||||
)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
const suffix = platform === 'win32' ? '.exe' : ''
|
||||
const entryName = `ntsilk-${platform}-${arch}${suffix}`
|
||||
|
||||
const load = async (ctx: ChronocatContext) => {
|
||||
const data = await new Promise<Buffer>((res, rej) => {
|
||||
new AdmZip(Buffer.from(ntsilkZip)).readFileAsync(entryName, (data, err) =>
|
||||
err ? rej(new Error(`读取文件失败`)) : res(data!),
|
||||
)
|
||||
})
|
||||
|
||||
const hash = getHash(data)
|
||||
|
||||
const dir = join(homedir(), `.chronocat/tmp/native`)
|
||||
|
||||
await mkdir(dir, {
|
||||
recursive: true,
|
||||
})
|
||||
|
||||
const path = join(dir, `${hash}${suffix}`)
|
||||
if (!(await ctx.chronocat.exists(path))) await writeFile(path, data)
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
const getHash = (data: BinaryLike) => {
|
||||
const hash = createHash('sha256')
|
||||
hash.update(data)
|
||||
return hash.digest('hex')
|
||||
}
|
6
packages/engine-media/src/types.d.ts
vendored
Normal file
6
packages/engine-media/src/types.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
declare const zipData: Uint8Array
|
||||
|
||||
declare module '*.zip' {
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default zipData
|
||||
}
|
@ -101,6 +101,16 @@ export interface SelfProfileDispatchMessage {
|
||||
}>
|
||||
}
|
||||
|
||||
export interface InternalMediaNtsilkEncodePayload {
|
||||
srcPath: string
|
||||
dstPath: string
|
||||
}
|
||||
|
||||
export interface InternalMediaNtsilkEncodeResponse {
|
||||
duration: number | undefined
|
||||
waveAmplitudes: number[] | undefined
|
||||
}
|
||||
|
||||
export interface SatoriMethods {
|
||||
'channel.get': [[ChannelGetPayload], Channel]
|
||||
'channel.list': [[ChannelListPayload], ChannelListResponse]
|
||||
@ -197,6 +207,11 @@ export interface CCInternalMethods {
|
||||
|
||||
'chronocat.internal.uix.uin.get': [[string], string | undefined]
|
||||
'chronocat.internal.uix.uin.get.group': [[string, string], string | undefined]
|
||||
|
||||
'chronocat.internal.media.ntsilk.encode': [
|
||||
[InternalMediaNtsilkEncodePayload],
|
||||
InternalMediaNtsilkEncodeResponse,
|
||||
]
|
||||
}
|
||||
|
||||
export type Methods = SatoriMethods & CCInternalMethods
|
||||
|
Loading…
Reference in New Issue
Block a user