@bililive-tools/manager
Version:
Batch scheduling recorders
134 lines (133 loc) • 6.15 kB
TypeScript
import { Emitter } from "mitt";
import { ChannelId, Message } from "./common.js";
import { RecorderCache } from "./cache.js";
import { RecorderCreateOpts, Recorder, SerializedRecorder, RecordHandle, DebugLog, Progress } from "./recorder.js";
import type { XmlStreamStats } from "./xml_stream_controller.js";
import { AnyObject, UnknownObject } from "./utils.js";
import { StreamManager } from "./downloader/streamManager.js";
export interface ProviderCheckConfig {
/** 检查循环间隔(毫秒) */
autoCheckInterval?: number;
/** 最大并发检查线程数 */
maxThreadCount?: number;
/** 每次检查之间的等待时间(毫秒) */
waitTime?: number;
}
export interface RecorderProvider<E extends AnyObject> {
id: string;
name: string;
siteURL: string;
matchURL: (this: RecorderProvider<E>, channelURL: string) => boolean;
resolveChannelInfoFromURL: (this: RecorderProvider<E>, channelURL: string) => Promise<{
id: ChannelId;
title: string;
owner: string;
uid?: number | string;
avatar?: string;
} | null>;
createRecorder: (this: RecorderProvider<E>, opts: Omit<RecorderCreateOpts<E>, "providerId">) => Recorder<E>;
fromJSON: <T extends SerializedRecorder<E>>(this: RecorderProvider<E>, json: T) => Recorder<E>;
setFFMPEGOutputArgs: (this: RecorderProvider<E>, args: string[]) => void;
}
declare const configurableProps: readonly ["savePathRule", "autoRemoveSystemReservedChars", "autoCheckInterval", "maxThreadCount", "waitTime", "ffmpegOutputArgs", "biliBatchQuery", "recordRetryImmediately", "providerCheckConfig"];
type ConfigurableProp = (typeof configurableProps)[number];
export interface RecorderManager<ME extends UnknownObject, P extends RecorderProvider<AnyObject> = RecorderProvider<UnknownObject>, PE extends AnyObject = GetProviderExtra<P>, E extends AnyObject = ME & PE> extends Emitter<{
error: {
source: string;
err: unknown;
};
RecordStart: {
recorder: SerializedRecorder<E>;
recordHandle: RecordHandle;
};
RecordSegment: {
recorder: SerializedRecorder<E>;
recordHandle?: RecordHandle;
};
videoFileCreated: {
recorder: SerializedRecorder<E>;
filename: string;
cover?: string;
rawFilename?: string;
};
videoFileCompleted: {
recorder: SerializedRecorder<E>;
filename: string;
stats?: XmlStreamStats;
};
RecorderProgress: {
recorder: SerializedRecorder<E>;
progress: Progress;
};
RecoderLiveStart: {
recorder: Recorder<E>;
};
RecordStop: {
recorder: SerializedRecorder<E>;
recordHandle: RecordHandle;
reason?: string;
};
Message: {
recorder: SerializedRecorder<E>;
message: Message;
};
RecorderUpdated: {
recorder: SerializedRecorder<E>;
keys: (string | keyof Recorder<E>)[];
};
RecorderAdded: SerializedRecorder<E>;
RecorderRemoved: SerializedRecorder<E>;
RecorderDebugLog: DebugLog & {
recorder: Recorder<E>;
};
Updated: ConfigurableProp[];
}> {
providers: P[];
getChannelURLMatchedRecorderProviders: (this: RecorderManager<ME, P, PE, E>, channelURL: string) => P[];
recorders: Recorder<E>[];
addRecorder: (this: RecorderManager<ME, P, PE, E>, opts: RecorderCreateOpts<E>) => Recorder<E>;
removeRecorder: (this: RecorderManager<ME, P, PE, E>, recorder: Recorder<E>) => void;
getRecorder: (this: RecorderManager<ME, P, PE, E>, id: string) => Recorder<E> | null;
startRecord: (this: RecorderManager<ME, P, PE, E>, id: string, opts?: {
ignoreDataLimit?: boolean;
}) => Promise<Recorder<E> | undefined>;
stopRecord: (this: RecorderManager<ME, P, PE, E>, id: string) => Promise<Recorder<E> | undefined>;
cutRecord: (this: RecorderManager<ME, P, PE, E>, id: string) => Promise<Recorder<E> | undefined>;
autoCheckInterval: number;
maxThreadCount: number;
waitTime: number;
isCheckLoopRunning: boolean;
startCheckLoop: (this: RecorderManager<ME, P, PE, E>) => void;
stopCheckLoop: (this: RecorderManager<ME, P, PE, E>) => void;
savePathRule: string;
autoRemoveSystemReservedChars: boolean;
ffmpegOutputArgs: string;
/** b站使用批量查询接口 */
biliBatchQuery: boolean;
/** 下播延迟检查 */
recordRetryImmediately: boolean;
/** 缓存系统 */
cache: RecorderCache;
/** 每个 provider 的检查配置 */
providerCheckConfig: Record<string, ProviderCheckConfig>;
/** 获取指定 provider 的检查配置(自动 fallback 到全局配置) */
getProviderCheckConfig: (this: RecorderManager<ME, P, PE, E>, providerId: string) => Required<ProviderCheckConfig>;
}
export type RecorderManagerCreateOpts<ME extends AnyObject = UnknownObject, P extends RecorderProvider<AnyObject> = RecorderProvider<UnknownObject>, PE extends AnyObject = GetProviderExtra<P>, E extends AnyObject = ME & PE> = Partial<Pick<RecorderManager<ME, P, PE, E>, ConfigurableProp>> & {
providers: P[];
/** 自定义缓存实现,不提供则使用默认的内存缓存 */
cache?: RecorderCache;
/** 每个 provider 的检查配置,key 为 provider.id */
providerCheckConfig?: Record<string, ProviderCheckConfig>;
};
export declare function createRecorderManager<ME extends AnyObject = UnknownObject, P extends RecorderProvider<AnyObject> = RecorderProvider<UnknownObject>, PE extends AnyObject = GetProviderExtra<P>, E extends AnyObject = ME & PE>(opts: RecorderManagerCreateOpts<ME, P, PE, E>): RecorderManager<ME, P, PE, E>;
export declare function genSavePathFromRule<ME extends AnyObject, P extends RecorderProvider<AnyObject>, PE extends AnyObject, E extends AnyObject>(manager: RecorderManager<ME, P, PE, E>, recorder: Recorder<E>, extData: {
owner: string;
title: string;
startTime: number;
liveStartTime: Date;
recordStartTime: Date;
extraMs?: boolean;
}): string;
export type GetProviderExtra<P> = P extends RecorderProvider<infer E> ? E : never;
export { StreamManager };