import os import shutil import subprocess import time import sys from pathlib import Path from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler from logger import get_system_logger, log_exception # ========================================== # 接口配置 # ========================================== STAGE_DIR = r'./stage' BACKUP_DIR = r'./backup' SESSION_DIR = r'./session' MIN_DURATION_SECONDS = 15 * 60 VIDEO_EXTS = {'.mp4', '.mkv', '.avi', '.mov', '.flv', '.wmv'} # 初始化日志 logger = get_system_logger('monitor') # ========================================== def get_video_duration(file_path): try: cmd = ['ffprobe', '-v', 'error', '-show_entries', 'format=duration', '-of', 'default=noprint_wrappers=1:nokey=1', str(file_path)] result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) duration = float(result.stdout) logger.debug(f"获取视频时长: {file_path.name} = {duration}秒") return duration except Exception as e: log_exception(logger, e, f"获取视频时长失败: {file_path}") return 0 class VideoHandler(FileSystemEventHandler): def on_created(self, event): if not event.is_directory: # 兼容处理 watchdog 路径编码问题 src_path = event.src_path if isinstance(src_path, bytes): src_path = src_path.decode('utf-8') logger.debug(f"检测到文件创建事件: {src_path}") self.handle_file(Path(src_path)) def handle_file(self, file_path): if file_path.suffix.lower() not in VIDEO_EXTS: logger.debug(f"跳过非视频文件: {file_path.name}") return logger.info(f"发现新视频文件: {file_path.name},正在检查写入状态...") # 改进:通过检查文件大小变化来判断是否写入完成 last_size = -1 while True: try: if not file_path.exists(): logger.warning(f"文件在检查期间消失: {file_path}") return current_size = file_path.stat().st_size if current_size == last_size and current_size > 0: break last_size = current_size time.sleep(5) # 每5秒检查一次大小 except Exception as e: logger.error(f"检查文件状态异常: {e}") break try: duration = get_video_duration(file_path) logger.info(f"视频时长: {file_path.name} = {duration/60:.1f} 分钟") if duration < MIN_DURATION_SECONDS: logger.info(f"时长不足 {MIN_DURATION_SECONDS/60:.0f} 分钟,移动到备份区") dst = Path(BACKUP_DIR) / file_path.name shutil.move(str(file_path), str(dst)) logger.info(f"已移动至备份: {dst}") else: # 核心联动:创建专属工作区 session_folder = Path(SESSION_DIR) / file_path.stem session_folder.mkdir(parents=True, exist_ok=True) logger.info(f"创建工作区: {session_folder}") logger.info(f"派发转录任务: {file_path.name}") # 改进:使用 sys.executable 保证环境一致性 process = subprocess.Popen([ sys.executable, 'video2srt.py', str(file_path), str(session_folder) ]) logger.info(f"转录进程已启动 (PID: {process.pid})") except Exception as e: log_exception(logger, e, "监控处理异常") if __name__ == "__main__": logger.info("="*50) logger.info("视频监控模块启动") logger.info("="*50) for d in [STAGE_DIR, BACKUP_DIR, SESSION_DIR]: Path(d).mkdir(parents=True, exist_ok=True) logger.info(f"监控目录: {STAGE_DIR}") logger.info(f"备份目录: {BACKUP_DIR}") logger.info(f"工作目录: {SESSION_DIR}") handler = VideoHandler() # 启动时扫描已有文件 logger.info("正在扫描 stage 目录下的存量视频...") for f in Path(STAGE_DIR).iterdir(): if f.is_file(): handler.handle_file(f) observer = Observer() observer.schedule(handler, STAGE_DIR, recursive=False) observer.start() logger.info("文件监控已启动") try: while True: time.sleep(1) except KeyboardInterrupt: logger.info("接收到停止信号,正在关闭...") observer.stop() observer.join() logger.info("视频监控模块已停止")