import os.path from datetime import datetime, timedelta from glob import glob from flask import Blueprint, jsonify, request, current_app from typing import Optional from config import BILILIVE_RECORDER_DIRECTORY, VIDEO_TITLE from model import db from model.DanmakuClip import DanmakuClip from model.VideoClip import VideoClip from model.Workflow import Workflow blueprint = Blueprint("api_bilirecorder", __name__, url_prefix="/api/bilirecorder") bili_record_workflow_item: Optional[Workflow] = None def clear_item(): global bili_record_workflow_item bili_record_workflow_item = None def commit_item(): global bili_record_workflow_item if bili_record_workflow_item is None: return bili_record_workflow_item.calculate_start_time() db.session.commit() def safe_create_item(): global bili_record_workflow_item if bili_record_workflow_item is None: bili_record_workflow_item = Workflow.query.filter( Workflow.update_time > (datetime.now() - timedelta(hours=8)), Workflow.automatic == 1 ).first() if bili_record_workflow_item is None: bili_record_workflow_item = Workflow() else: if bili_record_workflow_item is not None and bili_record_workflow_item.id is not None: bili_record_workflow_item.editing = False commit_item() bili_record_workflow_item = Workflow() if bili_record_workflow_item is None: bili_record_workflow_item = Workflow() bili_record_workflow_item.name = VIDEO_TITLE.format(datetime.now().strftime("%Y%m%d")) bili_record_workflow_item.automatic = True bili_record_workflow_item.editing = True db.session.commit() return bili_record_workflow_item def safe_get_item() -> Workflow: global bili_record_workflow_item if bili_record_workflow_item is None: return safe_create_item() return bili_record_workflow_item def collect_danmaku_files(workflow: Optional[Workflow]): if workflow is None: return clip: VideoClip for clip in workflow.video_clips: full_path = clip.full_path pre_file_name = os.path.splitext(full_path)[0] # 理论上也只有一个结果 for danmaku_file in glob("{}*xml".format(pre_file_name)): if os.path.exists(danmaku_file): relpath = os.path.relpath(danmaku_file, BILILIVE_RECORDER_DIRECTORY) # 确认是否已经添加 already_add = False for danmaku_clip in workflow.danmaku_clips: if danmaku_clip.file == relpath and danmaku_clip.base_path == BILILIVE_RECORDER_DIRECTORY: already_add = True break if not already_add: danmaku = DanmakuClip() danmaku.file = relpath danmaku.base_path = BILILIVE_RECORDER_DIRECTORY danmaku.offset = 0 danmaku.workflow = workflow db.session.add(danmaku) workflow.danmaku_clips.append(danmaku) commit_item() @blueprint.post("/") def bilirecorder_event(): payload = request.json current_app.logger.debug(payload) if 'EventType' not in payload: response = jsonify({ 'error': "异常", 'payload': payload, }) response.status_code = 403 return response if payload['EventType'] == "SessionStarted": # 录制开始 safe_create_item() elif payload['EventType'] == "SessionEnded": # 录制结束 item = safe_get_item() item.editing = False commit_item() clear_item() return jsonify(item.to_dict()) elif payload['EventType'] == "FileClosed": # 文件关闭 item = safe_get_item() event_data = payload.get("EventData", {}) video_file = event_data.get("RelativePath", None) # 判断是否重复 already_add = False for clip in item.video_clips: if video_file == clip.file and clip.base_path == BILILIVE_RECORDER_DIRECTORY: already_add = True break if not already_add: video_clip = VideoClip() video_clip.file = video_file video_clip.base_path = BILILIVE_RECORDER_DIRECTORY video_clip.duration = event_data.get("Duration", 0) item.video_clips.append(video_clip) commit_item() collect_danmaku_files(item) return jsonify(item.to_dict()) commit_item() item = safe_get_item() return jsonify(item.to_dict())