mirror of
https://github.com/Hommy-master/capcut-mate.git
synced 2026-08-30 17:48:47 +08:00
修改路径为URL,不下载,临时上库2
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@@ -13,6 +13,28 @@ class EasyCreateMaterialRequest(BaseModel):
|
||||
font_size: int = Field(default=15, description="字体大小")
|
||||
text_transform_y: int = Field(default=0, description="文字Y轴位置偏移")
|
||||
|
||||
@staticmethod
|
||||
def _is_http_url(url: str) -> bool:
|
||||
return isinstance(url, str) and url.startswith(("http://", "https://"))
|
||||
|
||||
@field_validator("audio_url")
|
||||
@classmethod
|
||||
def validate_audio_url(cls, value: str) -> str:
|
||||
"""音频 URL 必须为 http/https。"""
|
||||
if not cls._is_http_url(value):
|
||||
raise ValueError("audio_url must start with http:// or https://")
|
||||
return value
|
||||
|
||||
@field_validator("img_url", "video_url")
|
||||
@classmethod
|
||||
def validate_optional_media_url(cls, value: Optional[str]) -> Optional[str]:
|
||||
"""可选图片/视频 URL 如有传值,必须为 http/https。"""
|
||||
if value is None:
|
||||
return value
|
||||
if not cls._is_http_url(value):
|
||||
raise ValueError("optional media URL must start with http:// or https://")
|
||||
return value
|
||||
|
||||
|
||||
class EasyCreateMaterialResponse(BaseModel):
|
||||
"""快速创建素材轨道响应参数"""
|
||||
|
||||
@@ -3,9 +3,7 @@ from src.pyJianYingDraft import ScriptFile, trange, AudioSceneEffectType, VideoS
|
||||
import src.pyJianYingDraft as draft
|
||||
from src.utils.draft_cache import DRAFT_CACHE
|
||||
from exceptions import CustomException, CustomError
|
||||
import os
|
||||
from src.utils import helper
|
||||
import config
|
||||
import json
|
||||
import asyncio
|
||||
from typing import List, Dict, Any, Tuple, Optional
|
||||
@@ -43,14 +41,12 @@ def _add_audios_internal(
|
||||
draft_id = validate_and_get_draft_id(draft_url)
|
||||
script: ScriptFile = DRAFT_CACHE[draft_id]
|
||||
|
||||
draft_audio_dir = create_audio_directory(draft_id)
|
||||
|
||||
audios = parse_audio_data(json_str=audio_infos)
|
||||
validate_audio_data(audios, draft_id)
|
||||
|
||||
track_name = add_audio_track(script)
|
||||
|
||||
audio_ids = add_audio_segments(script, track_name, draft_audio_dir, audios)
|
||||
audio_ids = add_audio_segments(script, track_name, audios)
|
||||
|
||||
script.save()
|
||||
logger.info(f"Draft saved successfully")
|
||||
@@ -128,15 +124,6 @@ def validate_and_get_draft_id(draft_url: str) -> str:
|
||||
return draft_id
|
||||
|
||||
|
||||
def create_audio_directory(draft_id: str) -> str:
|
||||
"""创建音频资源存储目录"""
|
||||
draft_dir = os.path.join(config.DRAFT_DIR, draft_id)
|
||||
draft_audio_dir = os.path.join(draft_dir, "assets", "audios")
|
||||
os.makedirs(name=draft_audio_dir, exist_ok=True)
|
||||
logger.info(f"Created audio directory: {draft_audio_dir}")
|
||||
return draft_audio_dir
|
||||
|
||||
|
||||
def validate_audio_data(audios: List[Dict[str, Any]], draft_id: str):
|
||||
"""验证音频数据是否为空"""
|
||||
if len(audios) == 0:
|
||||
@@ -154,12 +141,12 @@ def add_audio_track(script: ScriptFile) -> str:
|
||||
return track_name
|
||||
|
||||
|
||||
def add_audio_segments(script: ScriptFile, track_name: str, draft_audio_dir: str, audios: List[Dict[str, Any]]) -> List[str]:
|
||||
def add_audio_segments(script: ScriptFile, track_name: str, audios: List[Dict[str, Any]]) -> List[str]:
|
||||
"""批量添加音频片段到指定轨道"""
|
||||
audio_ids = []
|
||||
for i, audio in enumerate(audios):
|
||||
try:
|
||||
audio_id = add_audio_to_draft(script, track_name, draft_audio_dir=draft_audio_dir, audio=audio)
|
||||
audio_id = add_audio_to_draft(script, track_name, audio=audio)
|
||||
audio_ids.append(audio_id)
|
||||
logger.info(f"Added audio {i+1}/{len(audios)}, audio_id: {audio_id}")
|
||||
except Exception as e:
|
||||
@@ -264,7 +251,6 @@ def add_audio_effect(audio_segment, audio_effect: str):
|
||||
def add_audio_to_draft(
|
||||
script: ScriptFile,
|
||||
track_name: str,
|
||||
draft_audio_dir: str,
|
||||
audio: dict
|
||||
) -> str:
|
||||
"""
|
||||
@@ -273,7 +259,6 @@ def add_audio_to_draft(
|
||||
Args:
|
||||
script: 草稿文件对象
|
||||
track_name: 音频轨道名称
|
||||
draft_audio_dir: 音频资源目录
|
||||
audio: 音频信息字典,包含以下字段:
|
||||
audio_url: 音频URL
|
||||
duration: 音频总时长(微秒),可选字段
|
||||
@@ -320,7 +305,7 @@ def add_audio_to_draft(
|
||||
return audio_segment.material_instance.material_id
|
||||
|
||||
except CustomException:
|
||||
logger.error(f"Add audio to draft failed, draft_audio_dir: {draft_audio_dir}, audio: {audio}")
|
||||
logger.error(f"Add audio to draft failed, audio: {audio}")
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Add audio to draft failed, error: {str(e)}")
|
||||
|
||||
@@ -4,9 +4,7 @@ import src.pyJianYingDraft as draft
|
||||
from src.utils.draft_cache import DRAFT_CACHE
|
||||
from exceptions import CustomException, CustomError
|
||||
from src.schemas.add_images import SegmentInfo
|
||||
import os
|
||||
from src.utils import helper
|
||||
import config
|
||||
import json
|
||||
import asyncio
|
||||
from typing import List, Dict, Any, Tuple, Optional
|
||||
@@ -93,11 +91,6 @@ def _add_images_internal(
|
||||
logger.error(f"Invalid draft URL or draft not found in cache, draft_id: {draft_id}")
|
||||
raise CustomException(CustomError.INVALID_DRAFT_URL)
|
||||
|
||||
draft_dir = os.path.join(config.DRAFT_DIR, draft_id)
|
||||
draft_image_dir = os.path.join(draft_dir, "assets", "images")
|
||||
os.makedirs(name=draft_image_dir, exist_ok=True)
|
||||
logger.info(f"Using image directory: {draft_image_dir}")
|
||||
|
||||
images = parse_image_data(json_str=image_infos)
|
||||
if len(images) == 0:
|
||||
logger.error(f"No image info provided, draft_id: {draft_id}")
|
||||
@@ -117,7 +110,6 @@ def _add_images_internal(
|
||||
try:
|
||||
segment_id, segment_info = add_image_to_draft(
|
||||
script, track_name,
|
||||
draft_image_dir=draft_image_dir,
|
||||
image=image,
|
||||
alpha=alpha,
|
||||
scale_x=scale_x,
|
||||
@@ -224,7 +216,6 @@ async def add_images_async(
|
||||
def add_image_to_draft(
|
||||
script: ScriptFile,
|
||||
track_name: str,
|
||||
draft_image_dir: str,
|
||||
image: dict,
|
||||
alpha: float = 1.0,
|
||||
scale_x: float = 1.0,
|
||||
@@ -238,7 +229,6 @@ def add_image_to_draft(
|
||||
Args:
|
||||
script: 草稿文件对象
|
||||
track_name: 视频轨道名称
|
||||
draft_image_dir: 图片资源目录
|
||||
image: 图片信息字典,包含以下字段:
|
||||
image_url: 图片URL
|
||||
width: 图片宽度(像素)
|
||||
@@ -395,7 +385,7 @@ def add_image_to_draft(
|
||||
return video_segment.segment_id, segment_info
|
||||
|
||||
except CustomException:
|
||||
logger.error(f"Add image to draft failed, draft_image_dir: {draft_image_dir}, image: {image}")
|
||||
logger.error(f"Add image to draft failed, image: {image}")
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Add image to draft failed, error: {str(e)}")
|
||||
|
||||
@@ -6,9 +6,7 @@ from src.pyJianYingDraft import ScriptFile, trange, IntroType
|
||||
import src.pyJianYingDraft as draft
|
||||
from src.utils.draft_cache import DRAFT_CACHE
|
||||
from exceptions import CustomException, CustomError
|
||||
import os
|
||||
from src.utils import helper
|
||||
import config
|
||||
import json
|
||||
from typing import List, Dict, Any, Tuple, Optional
|
||||
from src.utils.draft_lock_manager import get_draft_lock_manager
|
||||
@@ -193,11 +191,6 @@ def _add_videos_internal(
|
||||
if (not draft_id) or (draft_id not in DRAFT_CACHE):
|
||||
raise CustomException(CustomError.INVALID_DRAFT_URL)
|
||||
|
||||
# 2. 创建保存视频资源的目录
|
||||
draft_dir = os.path.join(config.DRAFT_DIR, draft_id)
|
||||
draft_video_dir = os.path.join(draft_dir, "assets", "videos")
|
||||
os.makedirs(name=draft_video_dir, exist_ok=True)
|
||||
|
||||
videos = parse_video_data(json_str=video_infos)
|
||||
if len(videos) == 0:
|
||||
logger.info(f"No video info, draft_id: {draft_id}")
|
||||
@@ -237,7 +230,7 @@ def _add_videos_internal(
|
||||
video['end'] = video['start'] + original_duration
|
||||
logger.info(f"Adjusted video {i} start time to {video['start']} for continuity, original_duration: {original_duration}")
|
||||
|
||||
segment_id, actual_duration = add_video_to_draft(script, track_name, draft_video_dir=draft_video_dir, video=video,
|
||||
segment_id, actual_duration = add_video_to_draft(script, track_name, video=video,
|
||||
scene_timeline=scene_timeline,
|
||||
alpha=alpha, scale_x=scale_x, scale_y=scale_y,
|
||||
transform_x=transform_x, transform_y=transform_y)
|
||||
@@ -295,7 +288,6 @@ def _has_valid_scene_timelines(
|
||||
def add_video_to_draft(
|
||||
script: ScriptFile,
|
||||
track_name: str,
|
||||
draft_video_dir: str,
|
||||
video: dict,
|
||||
scene_timeline: Optional[Dict[str, int]] = None,
|
||||
alpha: float = 1.0,
|
||||
@@ -310,7 +302,6 @@ def add_video_to_draft(
|
||||
Args:
|
||||
script: 草稿文件对象
|
||||
track_name: 视频轨道名称
|
||||
draft_video_dir: 视频资源目录
|
||||
video: 视频信息字典,包含以下字段:
|
||||
video_url: 视频URL
|
||||
width: 视频宽度(像素)
|
||||
@@ -414,7 +405,7 @@ def add_video_to_draft(
|
||||
# 8. 返回片段ID和实际播放时长(注意:是segment_id而不是material_id)
|
||||
return video_segment.segment_id, actual_duration
|
||||
except CustomException:
|
||||
logger.info(f"Add video to draft failed, draft_video_dir: {draft_video_dir}, video: {video}")
|
||||
logger.info(f"Add video to draft failed, video: {video}")
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Add video to draft failed, error: {str(e)}")
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import json
|
||||
import os
|
||||
from typing import Optional
|
||||
from urllib.parse import urlparse
|
||||
import asyncio
|
||||
|
||||
from src.utils.logger import logger
|
||||
@@ -10,7 +8,6 @@ import src.pyJianYingDraft as draft
|
||||
from src.utils.draft_cache import DRAFT_CACHE
|
||||
from exceptions import CustomException, CustomError
|
||||
from src.utils import helper
|
||||
import config
|
||||
from src.utils.draft_lock_manager import DraftLockManager
|
||||
|
||||
|
||||
@@ -52,36 +49,31 @@ def easy_create_material(
|
||||
logger.error(f"Invalid draft_url or draft not found in cache: {draft_url}")
|
||||
raise CustomException(CustomError.INVALID_DRAFT_URL)
|
||||
|
||||
# 2. 验证音频URL(必选参数)
|
||||
if not audio_url or audio_url.lower() == "null" or audio_url.strip() == "":
|
||||
logger.error("Audio URL is required and cannot be empty or null")
|
||||
raise CustomException(CustomError.MATERIAL_CREATE_FAILED)
|
||||
|
||||
# 3. 从缓存中获取草稿
|
||||
# 2. 从缓存中获取草稿
|
||||
script: ScriptFile = DRAFT_CACHE[draft_id]
|
||||
logger.info(f"Retrieved script from cache, draft_id: {draft_id}")
|
||||
|
||||
try:
|
||||
# 4. 添加音频(必须的)
|
||||
audio_added = add_audio_material(script, draft_id, audio_url)
|
||||
# 3. 添加音频(必须的)
|
||||
audio_added = add_audio_material(script, audio_url)
|
||||
logger.info(f"Audio material added: {audio_added}")
|
||||
|
||||
# 5. 添加视频(如果提供)
|
||||
if video_url and video_url.strip() and video_url.lower() != "null":
|
||||
video_added = add_video_material(script, draft_id, video_url)
|
||||
# 4. 添加视频(如果提供)
|
||||
if video_url:
|
||||
video_added = add_video_material(script, video_url)
|
||||
logger.info(f"Video material added: {video_added}")
|
||||
|
||||
# 6. 添加图片(如果提供)
|
||||
if img_url and img_url.strip() and img_url.lower() != "null":
|
||||
image_added = add_image_material(script, draft_id, img_url)
|
||||
# 5. 添加图片(如果提供)
|
||||
if img_url:
|
||||
image_added = add_image_material(script, img_url)
|
||||
logger.info(f"Image material added: {image_added}")
|
||||
|
||||
# 7. 添加文字(如果提供)
|
||||
# 6. 添加文字(如果提供)
|
||||
if text and text.strip():
|
||||
text_added = add_text_material(script, text, text_color, font_size, text_transform_y)
|
||||
logger.info(f"Text material added: {text_added}")
|
||||
|
||||
# 8. 保存草稿
|
||||
# 7. 保存草稿
|
||||
script.save()
|
||||
logger.info(f"Draft saved successfully")
|
||||
|
||||
@@ -174,18 +166,16 @@ async def easy_create_material_async(
|
||||
logger.info(f"Lock released for draft_id: {draft_id}")
|
||||
|
||||
|
||||
def add_video_material(script: ScriptFile, draft_id: str, video_url: str) -> bool:
|
||||
def add_video_material(script: ScriptFile, video_url: str) -> bool:
|
||||
"""
|
||||
添加视频素材到草稿(固定5秒时长)
|
||||
|
||||
与add_videos接口保持一致的处理方式:
|
||||
1. 创建规范的视频资源目录
|
||||
2. 使用parse_video_data解析视频信息
|
||||
3. 调用add_video_to_draft添加视频
|
||||
1. 使用parse_video_data解析视频信息
|
||||
2. 调用add_video_to_draft添加视频
|
||||
|
||||
Args:
|
||||
script: 草稿文件对象
|
||||
draft_id: 草稿ID
|
||||
video_url: 视频文件URL
|
||||
|
||||
Returns:
|
||||
@@ -194,13 +184,7 @@ def add_video_material(script: ScriptFile, draft_id: str, video_url: str) -> boo
|
||||
try:
|
||||
logger.info(f"Adding video material: {video_url}")
|
||||
|
||||
# 1. 创建视频资源目录(与add_videos保持一致)
|
||||
draft_dir = os.path.join(config.DRAFT_DIR, draft_id)
|
||||
draft_video_dir = os.path.join(draft_dir, "assets", "videos")
|
||||
os.makedirs(name=draft_video_dir, exist_ok=True)
|
||||
logger.info(f"Created video directory: {draft_video_dir}")
|
||||
|
||||
# 2. 构造视频信息JSON(固定5秒时长)
|
||||
# 1. 构造视频信息JSON(固定5秒时长)
|
||||
video_infos = json.dumps([{
|
||||
"video_url": video_url,
|
||||
"width": 1920,
|
||||
@@ -211,20 +195,20 @@ def add_video_material(script: ScriptFile, draft_id: str, video_url: str) -> boo
|
||||
"volume": 1.0
|
||||
}])
|
||||
|
||||
# 3. 解析视频信息
|
||||
# 2. 解析视频信息
|
||||
from src.service.add_videos import parse_video_data, add_video_to_draft
|
||||
video_items = parse_video_data(video_infos)
|
||||
if not video_items:
|
||||
logger.error("No video items parsed")
|
||||
return False
|
||||
|
||||
# 4. 添加视频轨道
|
||||
# 3. 添加视频轨道
|
||||
track_name = f"video_track_{helper.gen_unique_id()}"
|
||||
script.add_track(track_type=TrackType.video, track_name=track_name, relative_index=10)
|
||||
logger.info(f"Added video track: {track_name}")
|
||||
|
||||
# 5. 添加视频到轨道(传递正确的视频资源目录)
|
||||
add_video_to_draft(script, track_name, draft_video_dir, video_items[0])
|
||||
# 4. 添加视频到轨道
|
||||
add_video_to_draft(script, track_name, video_items[0])
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
@@ -232,18 +216,16 @@ def add_video_material(script: ScriptFile, draft_id: str, video_url: str) -> boo
|
||||
return False
|
||||
|
||||
|
||||
def add_image_material(script: ScriptFile, draft_id: str, img_url: str) -> bool:
|
||||
def add_image_material(script: ScriptFile, img_url: str) -> bool:
|
||||
"""
|
||||
添加图片素材到草稿
|
||||
|
||||
与add_images接口保持一致的处理方式:
|
||||
1. 创建规范的图片资源目录
|
||||
2. 使用parse_image_data解析图片信息
|
||||
3. 调用add_image_to_draft添加图片
|
||||
1. 使用parse_image_data解析图片信息
|
||||
2. 调用add_image_to_draft添加图片
|
||||
|
||||
Args:
|
||||
script: 草稿文件对象
|
||||
draft_id: 草稿ID
|
||||
img_url: 图片文件URL
|
||||
|
||||
Returns:
|
||||
@@ -252,13 +234,7 @@ def add_image_material(script: ScriptFile, draft_id: str, img_url: str) -> bool:
|
||||
try:
|
||||
logger.info(f"Adding image material: {img_url}")
|
||||
|
||||
# 1. 创建图片资源目录(与add_images保持一致)
|
||||
draft_dir = os.path.join(config.DRAFT_DIR, draft_id)
|
||||
draft_image_dir = os.path.join(draft_dir, "assets", "images")
|
||||
os.makedirs(name=draft_image_dir, exist_ok=True)
|
||||
logger.info(f"Created image directory: {draft_image_dir}")
|
||||
|
||||
# 2. 构造图片信息JSON(默认尺寸和3秒显示时长)
|
||||
# 1. 构造图片信息JSON(默认尺寸和3秒显示时长)
|
||||
image_infos = json.dumps([{
|
||||
"image_url": img_url,
|
||||
"width": 1024,
|
||||
@@ -267,20 +243,20 @@ def add_image_material(script: ScriptFile, draft_id: str, img_url: str) -> bool:
|
||||
"end": 3000000, # 3秒(3 * 1000000微秒)
|
||||
}])
|
||||
|
||||
# 3. 解析图片信息
|
||||
# 2. 解析图片信息
|
||||
from src.service.add_images import parse_image_data, add_image_to_draft
|
||||
image_items = parse_image_data(image_infos)
|
||||
if not image_items:
|
||||
logger.error("No image items parsed")
|
||||
return False
|
||||
|
||||
# 4. 添加图片轨道
|
||||
# 3. 添加图片轨道
|
||||
track_name = f"image_track_{helper.gen_unique_id()}"
|
||||
script.add_track(track_type=TrackType.video, track_name=track_name, relative_index=10)
|
||||
logger.info(f"Added image track: {track_name}")
|
||||
|
||||
# 5. 添加图片到轨道(传递正确的图片资源目录)
|
||||
add_image_to_draft(script, track_name, draft_image_dir, image_items[0])
|
||||
# 4. 添加图片到轨道
|
||||
add_image_to_draft(script, track_name, image_items[0])
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
@@ -288,18 +264,16 @@ def add_image_material(script: ScriptFile, draft_id: str, img_url: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def add_audio_material(script: ScriptFile, draft_id: str, audio_url: str) -> bool:
|
||||
def add_audio_material(script: ScriptFile, audio_url: str) -> bool:
|
||||
"""
|
||||
添加音频素材到草稿(固定5秒时长)
|
||||
|
||||
与add_audios接口保持一致的处理方式:
|
||||
1. 创建规范的音频资源目录
|
||||
2. 使用parse_audio_data解析音频信息
|
||||
3. 调用add_audio_to_draft添加音频
|
||||
1. 使用parse_audio_data解析音频信息
|
||||
2. 调用add_audio_to_draft添加音频
|
||||
|
||||
Args:
|
||||
script: 草稿文件对象
|
||||
draft_id: 草稿ID
|
||||
audio_url: 音频文件URL
|
||||
|
||||
Returns:
|
||||
@@ -308,13 +282,7 @@ def add_audio_material(script: ScriptFile, draft_id: str, audio_url: str) -> boo
|
||||
try:
|
||||
logger.info(f"Adding audio material: {audio_url}")
|
||||
|
||||
# 1. 创建音频资源目录(与add_audios保持一致)
|
||||
draft_dir = os.path.join(config.DRAFT_DIR, draft_id)
|
||||
draft_audio_dir = os.path.join(draft_dir, "assets", "audios")
|
||||
os.makedirs(name=draft_audio_dir, exist_ok=True)
|
||||
logger.info(f"Created audio directory: {draft_audio_dir}")
|
||||
|
||||
# 2. 构造音频信息JSON(固定5秒时长)
|
||||
# 1. 构造音频信息JSON(固定5秒时长)
|
||||
audio_infos = json.dumps([{
|
||||
"audio_url": audio_url,
|
||||
"start": 0,
|
||||
@@ -322,20 +290,20 @@ def add_audio_material(script: ScriptFile, draft_id: str, audio_url: str) -> boo
|
||||
"volume": 1.0
|
||||
}])
|
||||
|
||||
# 3. 解析音频信息
|
||||
# 2. 解析音频信息
|
||||
from src.service.add_audios import parse_audio_data, add_audio_to_draft
|
||||
audio_items = parse_audio_data(audio_infos)
|
||||
if not audio_items:
|
||||
logger.error("No audio items parsed")
|
||||
return False
|
||||
|
||||
# 4. 添加音频轨道
|
||||
# 3. 添加音频轨道
|
||||
track_name = f"audio_track_{helper.gen_unique_id()}"
|
||||
script.add_track(track_type=TrackType.audio, track_name=track_name, relative_index=10)
|
||||
logger.info(f"Added audio track: {track_name}")
|
||||
|
||||
# 5. 添加音频到轨道(传递正确的音频资源目录)
|
||||
add_audio_to_draft(script, track_name, draft_audio_dir, audio_items[0])
|
||||
# 4. 添加音频到轨道
|
||||
add_audio_to_draft(script, track_name, audio_items[0])
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
@@ -435,19 +403,3 @@ def hex_to_rgb(hex_color: str) -> list:
|
||||
logger.warning(f"Failed to parse hex color: {hex_color}, using default white")
|
||||
return [1.0, 1.0, 1.0] # 默认白色
|
||||
|
||||
|
||||
def validate_url(url: str) -> bool:
|
||||
"""
|
||||
验证URL格式是否正确
|
||||
|
||||
Args:
|
||||
url: 待验证的URL
|
||||
|
||||
Returns:
|
||||
URL是否有效
|
||||
"""
|
||||
try:
|
||||
result = urlparse(url)
|
||||
return all([result.scheme, result.netloc])
|
||||
except Exception:
|
||||
return False
|
||||
@@ -48,7 +48,6 @@ class TestAddVideosAsync:
|
||||
# Mock 所有依赖
|
||||
with patch('src.service.add_videos.helper.get_url_param') as mock_get_param, \
|
||||
patch('src.service.add_videos.DRAFT_CACHE') as mock_cache, \
|
||||
patch('src.service.add_videos.os.makedirs'), \
|
||||
patch('src.service.add_videos.parse_video_data') as mock_parse, \
|
||||
patch('src.service.add_videos.add_video_to_draft') as mock_add:
|
||||
|
||||
@@ -148,7 +147,6 @@ class TestAddVideosAsync:
|
||||
|
||||
with patch("src.service.add_videos.helper.get_url_param", return_value="concurrent-test"), \
|
||||
patch("src.service.add_videos.DRAFT_CACHE") as mock_cache, \
|
||||
patch("src.service.add_videos.os.makedirs"), \
|
||||
patch("src.service.add_videos.parse_video_data", return_value=[{
|
||||
"video_url": "https://example.com/video.mp4",
|
||||
"start": 0,
|
||||
@@ -221,7 +219,6 @@ class TestAddVideosAsync:
|
||||
"duration": 5000000,
|
||||
}]), \
|
||||
patch("src.service.add_videos.DRAFT_CACHE") as mock_cache, \
|
||||
patch("src.service.add_videos.os.makedirs"), \
|
||||
patch("src.service.add_videos.add_video_to_draft") as mock_add:
|
||||
|
||||
mock_cache.__contains__.return_value = True
|
||||
|
||||
@@ -134,9 +134,7 @@ class TestAllAsyncLockAPIs:
|
||||
|
||||
with patch('src.service.add_images.DRAFT_CACHE') as mock_cache, \
|
||||
patch('src.service.add_images.helper.get_url_param', return_value=mock_draft_data['draft_id']), \
|
||||
patch('src.service.add_images.draft.VideoSegment', return_value=mock_img_seg), \
|
||||
patch('src.service.add_images.os.makedirs'), \
|
||||
patch('src.service.add_images.os.path.isfile', return_value=True):
|
||||
patch('src.service.add_images.draft.VideoSegment', return_value=mock_img_seg):
|
||||
|
||||
# 模拟草稿对象(prepare 阶段会执行 draft_id in DRAFT_CACHE)
|
||||
mock_script = MagicMock()
|
||||
|
||||
@@ -10,6 +10,7 @@ from src.pyJianYingDraft.local_materials import VideoMaterial, AudioMaterial
|
||||
from src.schemas.add_images import AddImagesRequest
|
||||
from src.schemas.add_videos import AddVideosRequest
|
||||
from src.schemas.add_audios import AddAudiosRequest
|
||||
from src.schemas.easy_create_material import EasyCreateMaterialRequest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -33,7 +34,6 @@ def test_add_image_to_draft_uses_url_for_material_path(draft_ctx):
|
||||
add_image_to_draft(
|
||||
script=draft_ctx["script"],
|
||||
track_name="image_track_1",
|
||||
draft_image_dir="/tmp/ignored",
|
||||
image={
|
||||
"image_url": "https://assets.jcaigc.cn/demo1.png",
|
||||
"width": 1024,
|
||||
@@ -56,7 +56,6 @@ def test_add_video_to_draft_uses_url_for_material_path(draft_ctx):
|
||||
add_video_to_draft(
|
||||
script=draft_ctx["script"],
|
||||
track_name="video_track_1",
|
||||
draft_video_dir="/tmp/ignored",
|
||||
video={
|
||||
"video_url": "https://assets.jcaigc.cn/demo1.mp4",
|
||||
"start": 0,
|
||||
@@ -77,7 +76,6 @@ def test_add_audio_to_draft_uses_url_for_material_path(draft_ctx):
|
||||
add_audio_to_draft(
|
||||
script=draft_ctx["script"],
|
||||
track_name="audio_track_1",
|
||||
draft_audio_dir="/tmp/ignored",
|
||||
audio={
|
||||
"audio_url": "https://assets.jcaigc.cn/demo1.mp3",
|
||||
"start": 0,
|
||||
@@ -151,3 +149,22 @@ def test_schema_rejects_non_http_audio_url():
|
||||
"end": 1000,
|
||||
}]),
|
||||
)
|
||||
|
||||
|
||||
def test_easy_create_material_schema_rejects_non_http_audio_url():
|
||||
"""easy_create_material 的 audio_url 应在 schema 阶段校验。"""
|
||||
with pytest.raises(Exception):
|
||||
EasyCreateMaterialRequest(
|
||||
draft_url="http://localhost/v1/get_draft?draft_id=draft-1",
|
||||
audio_url="file:///tmp/demo1.mp3",
|
||||
)
|
||||
|
||||
|
||||
def test_easy_create_material_schema_rejects_non_http_optional_media_url():
|
||||
"""easy_create_material 的 img_url/video_url 如有值必须为 http/https。"""
|
||||
with pytest.raises(Exception):
|
||||
EasyCreateMaterialRequest(
|
||||
draft_url="http://localhost/v1/get_draft?draft_id=draft-1",
|
||||
audio_url="https://assets.jcaigc.cn/test1.mp3",
|
||||
img_url="ftp://example.com/demo1.png",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user