Skip to main content
Glama

JianYing MCP

by hey-jian-wei
text.py14.5 kB
# -*- coding: utf-8 -*- """ Author: jian wei File Name:text.py """ import json import os import uuid from typing import Optional, Dict, Any from dotenv import load_dotenv # 加载环境变量 load_dotenv() # 获取环境变量 SAVE_PATH = os.getenv('SAVE_PATH') from jianyingdraft.jianying.track import Track from jianyingdraft.validators.overlap_validator import validate_overlap class TextSegment: """ 文本片段管理类 负责文本片段的创建和数据存储 """ def __init__(self, draft_id: str, track_name: str = None,text_segment_id= None): """ 初始化文本片段 Args: draft_id: 草稿ID track_name: 指定的轨道名称(可选) text_segment_id:文本id,在添加动画、特效等可用,创建文本时不用 """ self.draft_id = draft_id self.track_name = track_name self.text_segment_id = text_segment_id def add_text_segment(self, text: str, timerange: str, font: Optional[str] = None, style: Optional[Dict[str, Any]] = None, clip_settings: Optional[Dict[str, Any]] = None, border: Optional[Dict[str, Any]] = None, background: Optional[Dict[str, Any]] = None, track_name: Optional[str] = None) -> Dict[str, Any]: """ 创建文本片段配置,可选的参数用户没要求可不填 Args: text: 文本内容 timerange: 时间范围,格式如 "0s-4.2s",表示在轨道上从0s开始,持续4.2s font: 字体类型名称(可选) style: 字体样式字典(可选),哪些需要修改就填哪些字段 默认style = { "size": 6.0,# 字体大小, 默认为6.0 "bold": False,# 是否加粗, 默认为否 "italic": False,# 是否斜体, 默认为否 "underline": False,# 是否加下划线, 默认为否 "color": (1.0, 1.0, 1.0), # 字体颜色, RGB三元组, 取值范围为[0, 1], 默认为白色 "alpha": 1.0,# 字体不透明度, 取值范围[0, 1], 默认不透明 "align": 0, # 对齐方式, 0: 左对齐, 1: 居中, 2: 右对齐, 默 认为左对齐 "vertical": False,#是否为竖排文本, 默认为否 "letter_spacing": 0,# 字符间距, 定义与剪映中一致, 默认为0 "line_spacing": 0,# 行间距, 定义与剪映中一致, 默认为0 "auto_wrapping": False,# 是否自动换行, 默认关闭 "max_line_width": 0.82 # 每行最大行宽占屏幕宽度比例, 取值范围为[0, 1], 默认为0.82 } clip_settings: 图像调节设置字典(可选),哪些需要修改就填哪些字段 默认 clip_settings = { "alpha": 1.0, # 图像不透明度, 0-1. 默认为1.0. "flip_horizontal": False, # 是否水平翻转. 默认为False. "flip_vertical": False, # 是否垂直翻转. 默认为False. "rotation": 0.0, # 顺时针旋转的**角度**, 可正可负. 默认为0.0. "scale_x": 1.0, # 水平缩放比例. 默认为1.0. "scale_y": 1.0, # 垂直缩放比例. 默认为1.0. "transform_x": 0.0, # 水平位移, 单位为半个画布宽. 默认为0.0. "transform_y": 0.0 # 垂直位移, 单位为半个画布高. 默认为0.0. } border: 文本描边参数字典(可选),哪些需要修改就填哪些字段 stroke_style = { "alpha": 1.0, # 描边不透明度, 取值范围[0, 1], 默认为1.0 "color": (0.0, 0.0, 0.0), # 描边颜色, RGB三元组, 取值范围为[0, 1], 默认为黑色 "width": 40.0 # 描边宽度, 与剪映中一致, 取值范围为[0, 100], 默认为40.0 } background: 文本背景参数字典(可选),哪些需要修改就填哪些字段 默认 background = { "color": "#000000", # 背景颜色, 格式为'#RRGGBB' (默认为黑色) "style": 1, # 背景样式, 1和2分别对应剪映中的两种样式, 默认为1 "alpha": 1.0, # 背景不透明度, 与剪映中一致, 取值范围[0, 1], 默认为1.0 "round_radius": 0.0, # 背景圆角半径, 与剪映中一致, 取值范围[0, 1], 默认为0.0 "height": 0. 14, # 背景高度, 与剪映中一致, 取值范围为[0, 1], 默认为0.14 "width": 0.14, # 背景宽度, 与剪映中一致, 取值范围为[0, 1], 默认为0.14 "horizontal_offset": 0.5, # 背景水平偏移, 与剪映中一致, 取值范围为[0, 1], 默认为0.5 "vertical_offset": 0.5 # 背景竖直偏移, 与剪映中一致, 取值范围为[0, 1], 默认为0.5 } track_name: 指定的轨道名称(可选),如果不指定则使用实例的track_name Returns: Dict[str, Any]: 构造的参数字典 """ self.text_segment_id = str(uuid.uuid4()) # 解析timerange if not timerange or "-" not in timerange: raise ValueError(f"Invalid timerange format: {timerange}") start_str, duration_str = timerange.split("-", 1) timerange_data = { "start": start_str.strip(), "duration": duration_str.strip() } # 构建add_text_segment参数(只保存用户传入的参数) add_text_segment_params = { "text": text, "timerange": timerange_data } # 只添加用户明确传入的可选参数 if font is not None: add_text_segment_params["font"] = font if style is not None: add_text_segment_params["style"] = style if clip_settings is not None: add_text_segment_params["clip_settings"] = clip_settings if border is not None: add_text_segment_params["border"] = border if background is not None: add_text_segment_params["background"] = background # 确定使用的轨道名称(参数优先,然后是实例属性) final_track_name = track_name or self.track_name # 验证轨道 if final_track_name: self._validate_track_for_text(final_track_name) # 验证片段重叠 if final_track_name: validate_overlap(self.draft_id, "text", final_track_name, timerange_data) # 构建完整的文本片段数据 text_segment_data = { "text_segment_id": self.text_segment_id, "operation": "add_text_segment", "add_text_segment": add_text_segment_params } # 只在指定了轨道名称时才添加track_name字段 if final_track_name: text_segment_data["track_name"] = final_track_name # 保存到文件 self.add_json_to_file(text_segment_data) return add_text_segment_params def add_animation(self, animation_type: str, animation_name: str, duration: Optional[str] = None,text_segment_id:Optional[str]=None) -> bool: """ 添加文本动画 Args: animation_type: 动画类型,"TextIntro"、"TextOutro"、"TextLoopAnim" animation_name: 动画名称,如 "复古打字机"、"弹簧"、"色差故障" 等 duration: 动画持续时间(可选),格式如 "1s"、"500ms" Returns: bool: 添加是否成功 """ if self.text_segment_id is None and text_segment_id is None: print("错误: text_segment_id不能为空") return False text_segment_id = text_segment_id or self.text_segment_id # 验证动画类型 valid_types = ["TextIntro", "TextOutro", "TextLoopAnim"] if animation_type not in valid_types: print(f"错误: 无效的动画类型 '{animation_type}',支持的类型: {valid_types}") return False # 构建add_animation参数 add_animation_params = { "animation_type": animation_type, "animation_name": animation_name } # 只添加用户明确传入的可选参数 if duration is not None: add_animation_params["duration"] = duration # 构建完整的动画数据 animation_data = { "text_segment_id": text_segment_id, "operation": "add_animation", "add_animation": add_animation_params } # 保存参数 self.add_json_to_file(animation_data) return True def add_bubble(self, effect_id: str, resource_id: str) -> bool: # 没有该效果,可不加这个方法 """ 添加文本气泡效果 Args: effect_id: 气泡效果的effect_id resource_id: 气泡效果的resource_id Returns: bool: 添加是否成功 """ if self.text_segment_id is None: print("错误: text_segment_id不能为空") return False # 验证参数 if not effect_id or not resource_id: print("错误: effect_id和resource_id不能为空") return False # 构建add_bubble参数 add_bubble_params = { "effect_id": effect_id, "resource_id": resource_id } # 构建完整的气泡数据 bubble_data = { "text_segment_id": self.text_segment_id, "operation": "add_bubble", "add_bubble": add_bubble_params } # 保存参数 self.add_json_to_file(bubble_data) return True def add_effect(self, effect_id: str) -> bool: # 没有该效果,可不加这个方法 """ 添加文本花字效果 Args: effect_id: 花字效果的effect_id,也同时是其resource_id Returns: bool: 添加是否成功 """ if self.text_segment_id is None: print("错误: text_segment_id不能为空") return False # 验证参数 if not effect_id: print("错误: effect_id不能为空") return False # 构建add_effect参数 add_effect_params = { "effect_id": effect_id } # 构建完整的花字效果数据 effect_data = { "text_segment_id": self.text_segment_id, "operation": "add_effect", "add_effect": add_effect_params } # 保存参数 self.add_json_to_file(effect_data) return True def add_json_to_file(self, new_data: Dict[str, Any]) -> bool: """ 向现有JSON文件中添加新的JSON数据,保持文件结构规范 Args: new_data: 要添加的新数据 Returns: bool: 添加是否成功 """ try: # 确保目录存在 os.makedirs(f"{SAVE_PATH}/{self.draft_id}", exist_ok=True) file_path = f"{SAVE_PATH}/{self.draft_id}/text.json" # 读取现有数据 existing_data = [] if os.path.exists(file_path): try: with open(file_path, 'r', encoding='utf-8') as f: existing_data = json.load(f) # 如果不是列表,转换为列表 if not isinstance(existing_data, list): existing_data = [existing_data] except (json.JSONDecodeError, FileNotFoundError): # 如果文件不存在或格式错误,初始化为空列表 existing_data = [] # 添加新数据 existing_data.append(new_data) # 保存为规范的JSON数组格式 with open(file_path, 'w', encoding='utf-8') as f: json.dump(existing_data, f, ensure_ascii=False, indent=2) return True except Exception as e: print(f"添加JSON数据失败: {e}") return False def get_text_segments(self) -> list: """ 获取所有文本片段记录 Returns: List: 文本片段记录列表 """ try: file_path = f"{SAVE_PATH}/{self.draft_id}/text.json" if os.path.exists(file_path): with open(file_path, 'r', encoding='utf-8') as f: return json.load(f) return [] except Exception as e: print(f"读取文本片段数据失败: {e}") return [] def get_text_segment_by_id(self, text_segment_id: str) -> Optional[Dict[str, Any]]: """ 根据文本片段ID获取文本片段信息 Args: text_segment_id: 文本片段ID Returns: Dict: 文本片段信息,如果不存在返回None """ text_segments = self.get_text_segments() for segment in text_segments: if segment.get("text_segment_id") == text_segment_id: return segment return None def _validate_track_for_text(self, track_name: str): """验证轨道是否适用于文本片段""" track_manager = Track(self.draft_id) # 检查轨道是否存在 if not track_manager.validate_track_exists(track_name): raise NameError(f"轨道不存在: {track_name}") # 检查轨道类型是否为文本类型 track_info = track_manager.get_track_by_name(track_name) if track_info: add_track_data = track_info.get("add_track", {}) track_type = add_track_data.get("track_type") if track_type != "text": raise TypeError(f"轨道 '{track_name}' 的类型是 '{track_type}',不能添加文本片段")

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hey-jian-wei/jianying-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server