127 lines
4.7 KiB
Python
127 lines
4.7 KiB
Python
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("视频监控模块已停止")
|