@@ -28,7 +28,7 @@ function toSrt(chunks: SplitChunk[]): string {
28
28
let counter = 1 ;
29
29
const lines : SrtLine [ ] = [ ] ;
30
30
for ( const c of chunks ) {
31
- const segments = c . response ?. segments ?? [ ] ;
31
+ const segments = c . response ?. segments ?? [ ] ;
32
32
for ( const segment of segments ) {
33
33
lines . push ( {
34
34
index : counter ,
@@ -43,6 +43,9 @@ function toSrt(chunks: SplitChunk[]): string {
43
43
return SrtUtil . toNewSrt ( lines ) ;
44
44
}
45
45
46
+ // 设置过期时间阈值,单位毫秒(此处示例为 3 小时)
47
+ const EXPIRATION_THRESHOLD = 3 * 60 * 60 * 1000 ;
48
+
46
49
@injectable ( )
47
50
class WhisperServiceImpl implements WhisperService {
48
51
@inject ( TYPES . DpTaskService )
@@ -88,7 +91,7 @@ class WhisperServiceImpl implements WhisperService {
88
91
// 判断是否需要重新分割转录:状态不为 processed、文件过期(3小时)或视频文件发生变化
89
92
const newVideoInfo = await this . ffmpegService . getVideoInfo ( filePath ) ;
90
93
const videoChanged = ! FileUtil . compareVideoInfo ( context . videoInfo , newVideoInfo ) ;
91
- const expired = Date . now ( ) - context . updatedTime > 3 * 60 * 60 * 1000 ; // 3 小时
94
+ const expired = Date . now ( ) - context . updatedTime > EXPIRATION_THRESHOLD ;
92
95
if ( context . state !== 'processed' || expired || videoChanged ) {
93
96
// 重新转换并分割
94
97
await this . convertAndSplit ( taskId , context ) ;
@@ -151,13 +154,14 @@ class WhisperServiceImpl implements WhisperService {
151
154
} catch ( error ) {
152
155
dpLog . error ( error ) ;
153
156
if ( ! ( error instanceof Error ) ) throw error ;
154
- const cancel = error instanceof CancelByUserError
157
+ const cancel = error instanceof CancelByUserError ;
155
158
this . dpTaskService . update ( {
156
159
id : taskId ,
157
160
status : cancel ? DpTaskState . CANCELLED : DpTaskState . FAILED ,
158
161
progress : cancel ? '任务取消' : error . message
159
162
} ) ;
160
163
}
164
+ await this . cleanExpiredFolders ( ) ;
161
165
}
162
166
163
167
/**
@@ -238,6 +242,54 @@ class WhisperServiceImpl implements WhisperService {
238
242
}
239
243
return tempDir ;
240
244
}
245
+
246
+ /**
247
+ * 扫描 whisper 的临时目录,删除超过有效期的目录
248
+ */
249
+ private cleanExpiredFolders ( ) : void {
250
+ try {
251
+ const whisperBaseDir = path . join (
252
+ this . locationService . getDetailLibraryPath ( LocationType . TEMP ) ,
253
+ 'whisper'
254
+ ) ;
255
+ if ( ! fs . existsSync ( whisperBaseDir ) ) return ;
256
+ const folders = fs . readdirSync ( whisperBaseDir ) ;
257
+ for ( const folderName of folders ) {
258
+ const folderPath = path . join ( whisperBaseDir , folderName ) ;
259
+ if ( ! fs . statSync ( folderPath ) . isDirectory ( ) ) continue ;
260
+ let folderExpired = false ;
261
+ const infoPath = path . join ( folderPath , WhisperServiceImpl . INFO_FILE ) ;
262
+ if ( fs . existsSync ( infoPath ) ) {
263
+ try {
264
+ const content = fs . readFileSync ( infoPath , { encoding : 'utf8' } ) ;
265
+ const info = JSON . parse ( content ) as Partial < WhisperContext > ;
266
+ // 检查 updatedTime 是否存在且是数字,否则直接认定为过期
267
+ if (
268
+ typeof info . updatedTime !== 'number' ||
269
+ Date . now ( ) - info . updatedTime > EXPIRATION_THRESHOLD
270
+ ) {
271
+ folderExpired = true ;
272
+ }
273
+ } catch ( err ) {
274
+ dpLog . warn (
275
+ `[WhisperService] 解析${ infoPath } 失败:${ err } ,将直接删除此目录`
276
+ ) ;
277
+ folderExpired = true ;
278
+ }
279
+ } else {
280
+ // info.json 不存在直接删除
281
+ folderExpired = true ;
282
+ }
283
+ if ( folderExpired ) {
284
+ dpLog . info ( `[WhisperService] 删除过期目录: ${ folderPath } ` ) ;
285
+ // 删除整个文件夹(包括目录下的所有内容)
286
+ fs . rmSync ( folderPath , { recursive : true , force : true } ) ;
287
+ }
288
+ }
289
+ } catch ( err ) {
290
+ dpLog . error ( `[WhisperService] 清理过期目录失败:${ err } ` ) ;
291
+ }
292
+ }
241
293
}
242
294
243
295
export default WhisperServiceImpl ;
0 commit comments