feat: 空镜素材配置后端化,视频生成流程重构
- 后端: 空镜素材迁移到 config/materials.json,duration从文件名_{N}s_自动解析
- 后端: 新增 POST /api/v1/materials/match 接口,后端做关键词匹配
- 前端: VideoGeneration 空镜匹配改为调用后端接口
- 前端: 人物出镜素材改为本地文件选择器直接选取,不走素材库
- 前端: 视频生成流程简化,移除Vidu对口型和七牛云上传
- Rust: 视频合成支持从随机起始时间截取人物素材片段
- Rust: 修复ffprobe参数错误(添加-show_entries format=duration)
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
空镜素材 API
|
||||
============
|
||||
|
||||
提供空镜素材匹配接口。
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.schemas.common import ApiResponse, success_response
|
||||
from app.schemas.materials import MatchMaterialRequest, MaterialInfo
|
||||
from app.services.material_service import match_material
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/match", response_model=ApiResponse[MaterialInfo | None])
|
||||
async def match_material_endpoint(request: MatchMaterialRequest):
|
||||
"""
|
||||
根据场景描述和所需时长匹配空镜素材
|
||||
|
||||
返回匹配到的素材信息,无匹配返回 data: null
|
||||
"""
|
||||
result = match_material(request.scene, request.duration)
|
||||
|
||||
if result is None:
|
||||
return success_response(data=None, message="未匹配到素材")
|
||||
|
||||
return success_response(
|
||||
data=MaterialInfo(url=result["url"], duration=result["duration"]),
|
||||
message="匹配成功",
|
||||
)
|
||||
@@ -8,9 +8,12 @@ from fastapi import APIRouter
|
||||
from app.api.v1 import (
|
||||
auth,
|
||||
caption,
|
||||
materials,
|
||||
script,
|
||||
system,
|
||||
tasks,
|
||||
upload,
|
||||
vidu,
|
||||
voice,
|
||||
)
|
||||
|
||||
@@ -33,3 +36,12 @@ api_router.include_router(caption.router, tags=["Caption"])
|
||||
|
||||
# 语音合成模块(TTS + 声音克隆)
|
||||
api_router.include_router(voice.router, tags=["Voice"])
|
||||
|
||||
# 文件上传模块
|
||||
api_router.include_router(upload.router, tags=["Upload"])
|
||||
|
||||
# Vidu 对口型模块
|
||||
api_router.include_router(vidu.router, tags=["Vidu"])
|
||||
|
||||
# 空镜素材模块
|
||||
api_router.include_router(materials.router, prefix="/materials", tags=["Materials"])
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
"""
|
||||
文件上传 API
|
||||
============
|
||||
|
||||
提供通用文件上传功能,直接上传到七牛云对象存储。
|
||||
"""
|
||||
|
||||
import logging
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
|
||||
import io
|
||||
|
||||
from fastapi import APIRouter, File, HTTPException, UploadFile
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.schemas.common import ApiResponse, success_response
|
||||
from app.services.qiniu_service import get_qiniu_service
|
||||
|
||||
router = APIRouter(prefix="/upload", tags=["Upload"])
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UploadResponse(BaseModel):
|
||||
"""上传响应"""
|
||||
|
||||
url: str = Field(..., description="七牛云文件 URL")
|
||||
key: str = Field(..., description="七牛云文件 key")
|
||||
size: int = Field(..., description="文件大小(字节)")
|
||||
|
||||
|
||||
@router.post("/video", response_model=ApiResponse[UploadResponse])
|
||||
async def upload_video(
|
||||
file: UploadFile = File(..., description="视频文件"),
|
||||
):
|
||||
"""
|
||||
上传视频到七牛云
|
||||
|
||||
支持格式:mp4, mov, avi, webm
|
||||
返回七牛云永久访问 URL。
|
||||
"""
|
||||
try:
|
||||
# 验证文件格式
|
||||
allowed_types = {
|
||||
"video/mp4",
|
||||
"video/quicktime",
|
||||
"video/x-msvideo",
|
||||
"video/webm",
|
||||
}
|
||||
content_type = file.content_type or ""
|
||||
|
||||
# 如果 content_type 为空,尝试从文件名推断
|
||||
if not content_type:
|
||||
ext = Path(file.filename or "").suffix.lower()
|
||||
ext_to_mime = {
|
||||
".mp4": "video/mp4",
|
||||
".mov": "video/quicktime",
|
||||
".avi": "video/x-msvideo",
|
||||
".webm": "video/webm",
|
||||
}
|
||||
content_type = ext_to_mime.get(ext, "")
|
||||
|
||||
if content_type not in allowed_types:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"不支持的文件格式: {content_type},请上传 mp4/mov/avi/webm 视频",
|
||||
)
|
||||
|
||||
# 读取文件内容
|
||||
content = await file.read()
|
||||
if not content:
|
||||
raise HTTPException(status_code=400, detail="文件内容为空")
|
||||
|
||||
# 生成唯一文件名
|
||||
ext = Path(file.filename or "video.mp4").suffix or ".mp4"
|
||||
unique_name = f"{uuid.uuid4().hex[:16]}{ext}"
|
||||
|
||||
# 上传到七牛云
|
||||
qiniu = get_qiniu_service()
|
||||
bucket, domain = qiniu._get_bucket_and_domain("video")
|
||||
key = qiniu.generate_key("video", unique_name)
|
||||
stream = io.BytesIO(content)
|
||||
result = qiniu.upload_stream(
|
||||
stream=stream,
|
||||
key=key,
|
||||
mime_type=content_type or "video/mp4",
|
||||
bucket=bucket,
|
||||
domain=domain,
|
||||
)
|
||||
|
||||
url = result.get("url")
|
||||
key = result.get("key")
|
||||
|
||||
if not url:
|
||||
raise HTTPException(status_code=500, detail="上传到七牛云失败:未返回 URL")
|
||||
|
||||
logger.info(f"[Upload] 视频上传成功: {url[:80]}..., size={len(content)}")
|
||||
|
||||
return success_response(
|
||||
data=UploadResponse(
|
||||
url=url,
|
||||
key=key or unique_name,
|
||||
size=len(content),
|
||||
)
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"[Upload] 视频上传失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"上传失败: {e}")
|
||||
|
||||
|
||||
@router.post("/image", response_model=ApiResponse[UploadResponse])
|
||||
async def upload_image(
|
||||
file: UploadFile = File(..., description="图片文件"),
|
||||
):
|
||||
"""
|
||||
上传图片到七牛云
|
||||
|
||||
支持格式:jpg, png, gif, webp
|
||||
"""
|
||||
try:
|
||||
allowed_types = {
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/gif",
|
||||
"image/webp",
|
||||
}
|
||||
content_type = file.content_type or ""
|
||||
|
||||
if not content_type:
|
||||
ext = Path(file.filename or "").suffix.lower()
|
||||
ext_to_mime = {
|
||||
".jpg": "image/jpeg",
|
||||
".jpeg": "image/jpeg",
|
||||
".png": "image/png",
|
||||
".gif": "image/gif",
|
||||
".webp": "image/webp",
|
||||
}
|
||||
content_type = ext_to_mime.get(ext, "")
|
||||
|
||||
if content_type not in allowed_types:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"不支持的图片格式: {content_type}",
|
||||
)
|
||||
|
||||
content = await file.read()
|
||||
if not content:
|
||||
raise HTTPException(status_code=400, detail="文件内容为空")
|
||||
|
||||
ext = Path(file.filename or "image.jpg").suffix or ".jpg"
|
||||
unique_name = f"{uuid.uuid4().hex[:16]}{ext}"
|
||||
|
||||
qiniu = get_qiniu_service()
|
||||
bucket, domain = qiniu._get_bucket_and_domain("image")
|
||||
key = qiniu.generate_key("image", unique_name)
|
||||
stream = io.BytesIO(content)
|
||||
result = qiniu.upload_stream(
|
||||
stream=stream,
|
||||
key=key,
|
||||
mime_type=content_type or "image/jpeg",
|
||||
bucket=bucket,
|
||||
domain=domain,
|
||||
)
|
||||
|
||||
url = result.get("url")
|
||||
key = result.get("key")
|
||||
|
||||
if not url:
|
||||
raise HTTPException(status_code=500, detail="上传到七牛云失败:未返回 URL")
|
||||
|
||||
logger.info(f"[Upload] 图片上传成功: {url[:80]}..., size={len(content)}")
|
||||
|
||||
return success_response(
|
||||
data=UploadResponse(
|
||||
url=url,
|
||||
key=key or unique_name,
|
||||
size=len(content),
|
||||
)
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"[Upload] 图片上传失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"上传失败: {e}")
|
||||
@@ -0,0 +1,159 @@
|
||||
"""
|
||||
Vidu API 代理路由
|
||||
================
|
||||
|
||||
提供 Vidu 对口型(lip-sync)任务的提交和查询接口。
|
||||
前端通过此接口提交任务并轮询状态,无需直接访问 Vidu API。
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.api.deps import get_current_user
|
||||
from app.models.user import User
|
||||
from app.schemas.common import ApiResponse, success_response
|
||||
from app.services.vidu_tts_service import ViduTTSService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/vidu", tags=["Vidu"])
|
||||
|
||||
|
||||
# ========== 请求/响应模型 ==========
|
||||
|
||||
|
||||
class LipSyncRequest(BaseModel):
|
||||
"""对口型请求"""
|
||||
|
||||
video_url: str = Field(..., min_length=1, description="原视频 URL")
|
||||
audio_url: str | None = Field(None, description="音频 URL(与 text 二选一)")
|
||||
text: str | None = Field(None, description="文本内容(与 audio_url 二选一)")
|
||||
voice_id: str | None = Field(None, description="音色 ID(文字驱动时生效)")
|
||||
speed: float = Field(default=1.0, ge=0.5, le=2.0, description="语速")
|
||||
volume: int = Field(default=0, ge=0, le=10, description="音量")
|
||||
ref_photo_url: str | None = Field(None, description="人脸参考图 URL")
|
||||
|
||||
@staticmethod
|
||||
def validate_at_least_one_audio_source(values: dict) -> dict:
|
||||
"""验证至少提供 audio_url 或 text 之一"""
|
||||
audio_url = values.get("audio_url")
|
||||
text = values.get("text")
|
||||
if not audio_url and not text:
|
||||
raise ValueError("必须提供 audio_url 或 text 之一")
|
||||
return values
|
||||
|
||||
|
||||
class LipSyncResponse(BaseModel):
|
||||
"""对口型任务提交响应"""
|
||||
|
||||
task_id: str = Field(..., description="Vidu 任务 ID")
|
||||
message: str = Field(default="任务已提交", description="状态消息")
|
||||
|
||||
|
||||
class LipSyncQueryResponse(BaseModel):
|
||||
"""对口型任务查询响应"""
|
||||
|
||||
task_id: str = Field(..., description="任务 ID")
|
||||
state: str = Field(..., description="任务状态: pending/processing/succeeded/failed")
|
||||
video_url: str | None = Field(None, description="生成后的视频 URL(成功时)")
|
||||
message: str | None = Field(None, description="状态描述或错误信息")
|
||||
creations: list[dict] | None = Field(None, description="Vidu 原始 creations 数据")
|
||||
|
||||
|
||||
# ========== API 路由 ==========
|
||||
|
||||
|
||||
@router.post("/lip-sync", response_model=ApiResponse[LipSyncResponse])
|
||||
async def create_lip_sync_task(
|
||||
request: LipSyncRequest,
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""
|
||||
提交 Vidu 对口型任务
|
||||
|
||||
需要提供:
|
||||
- video_url: 原视频 URL(人物出镜视频)
|
||||
- audio_url: 音频 URL(与 text 二选一)
|
||||
- text: 文本内容(与 audio_url 二选一,使用 Vidu 内置 TTS)
|
||||
|
||||
返回 Vidu task_id,用于后续轮询查询。
|
||||
"""
|
||||
try:
|
||||
# 验证至少提供一种音频来源
|
||||
if not request.audio_url and not request.text:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="必须提供 audio_url 或 text 之一",
|
||||
)
|
||||
|
||||
service = ViduTTSService()
|
||||
task_id = await service.lip_sync_create(
|
||||
video_url=request.video_url,
|
||||
audio_url=request.audio_url,
|
||||
text=request.text,
|
||||
voice_id=request.voice_id,
|
||||
speed=request.speed,
|
||||
volume=request.volume,
|
||||
ref_photo_url=request.ref_photo_url,
|
||||
)
|
||||
|
||||
logger.info(f"[Vidu] 对口型任务提交成功: task_id={task_id}, user={current_user.id}")
|
||||
|
||||
return success_response(
|
||||
data=LipSyncResponse(
|
||||
task_id=task_id,
|
||||
message="对口型任务已提交,请轮询查询状态",
|
||||
)
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"[Vidu] 提交对口型任务失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"提交对口型任务失败: {e}")
|
||||
|
||||
|
||||
@router.get("/tasks/{task_id}/creations", response_model=ApiResponse[LipSyncQueryResponse])
|
||||
async def query_lip_sync_task(
|
||||
task_id: str,
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""
|
||||
查询 Vidu 对口型任务状态
|
||||
|
||||
返回任务状态及生成物信息。
|
||||
当 state=succeeded 时,video_url 为生成后的对口型视频 URL。
|
||||
"""
|
||||
try:
|
||||
service = ViduTTSService()
|
||||
result = await service.lip_sync_query(task_id)
|
||||
|
||||
state = result.get("state", "unknown")
|
||||
creations = result.get("creations", [])
|
||||
|
||||
# 提取视频 URL(成功时)
|
||||
video_url = None
|
||||
if state == "succeeded" and creations:
|
||||
# creations 是数组,取第一个
|
||||
first_creation = creations[0] if creations else {}
|
||||
video_url = first_creation.get("url")
|
||||
|
||||
logger.info(
|
||||
f"[Vidu] 查询对口型任务: task_id={task_id}, state={state}, user={current_user.id}"
|
||||
)
|
||||
|
||||
return success_response(
|
||||
data=LipSyncQueryResponse(
|
||||
task_id=task_id,
|
||||
state=state,
|
||||
video_url=video_url,
|
||||
message=result.get("message") if state == "failed" else None,
|
||||
creations=creations if creations else None,
|
||||
)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[Vidu] 查询对口型任务失败: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"查询任务失败: {e}")
|
||||
@@ -79,6 +79,15 @@ async def lifespan(app: FastAPI):
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to load models from config: {e}")
|
||||
|
||||
# 加载空镜素材配置(从 JSON 文件)
|
||||
try:
|
||||
from app.services.material_service import load_config
|
||||
|
||||
load_config()
|
||||
logger.info("Loaded material config from JSON file")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to load material config: {e}")
|
||||
|
||||
yield
|
||||
|
||||
# 关闭时清理
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
空镜素材 Schema
|
||||
==============
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class MaterialInfo(BaseModel):
|
||||
"""素材条目"""
|
||||
|
||||
url: str = Field(description="素材 URL(远程或本地路径)")
|
||||
duration: float = Field(description="素材时长(秒),从文件名解析)")
|
||||
|
||||
|
||||
class MatchMaterialRequest(BaseModel):
|
||||
"""匹配素材请求"""
|
||||
|
||||
scene: str = Field(description="分镜场景描述")
|
||||
duration: float = Field(description="所需时长(秒)")
|
||||
@@ -0,0 +1,81 @@
|
||||
"""
|
||||
空镜素材服务
|
||||
============
|
||||
|
||||
从本地 JSON 配置文件加载素材库,提供匹配逻辑。
|
||||
duration 从文件名 `_{N}s_` 中自动解析。
|
||||
"""
|
||||
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
# 正则:从文件名中提取时长,如 plumbing_10s_a23f8fcb.mp4 → 10
|
||||
_DURATION_RE = re.compile(r"_(\d+)s_")
|
||||
|
||||
# 配置缓存(启动时加载,运行时只读)
|
||||
_keywords: dict[str, str] = {}
|
||||
_materials: dict[str, list[dict]] = {}
|
||||
|
||||
|
||||
def _get_config_path() -> Path:
|
||||
"""获取配置文件绝对路径"""
|
||||
# 配置文件位于项目根目录的 config/ 下
|
||||
return Path(__file__).resolve().parent.parent.parent / "config" / "materials.json"
|
||||
|
||||
|
||||
def _parse_duration(url: str) -> float:
|
||||
"""从 URL 文件名中解析时长(秒)"""
|
||||
filename = url.split("/")[-1]
|
||||
match = _DURATION_RE.search(filename)
|
||||
if not match:
|
||||
raise ValueError(f"无法从文件名解析时长: {filename}")
|
||||
return float(match.group(1))
|
||||
|
||||
|
||||
def load_config() -> None:
|
||||
"""加载素材配置到内存缓存"""
|
||||
global _keywords, _materials
|
||||
|
||||
config_path = _get_config_path()
|
||||
if not config_path.exists():
|
||||
raise FileNotFoundError(f"素材配置文件不存在: {config_path}")
|
||||
|
||||
with open(config_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
_keywords = data.get("keywords", {})
|
||||
raw_materials = data.get("materials", {})
|
||||
|
||||
# 解析每个素材的 duration
|
||||
_materials = {}
|
||||
for slug, entries in raw_materials.items():
|
||||
parsed = []
|
||||
for entry in entries:
|
||||
url = entry["url"]
|
||||
duration = _parse_duration(url)
|
||||
parsed.append({"url": url, "duration": duration})
|
||||
_materials[slug] = parsed
|
||||
|
||||
|
||||
def match_material(scene: str, required_duration: float) -> dict | None:
|
||||
"""
|
||||
根据场景描述和所需时长匹配空镜素材
|
||||
|
||||
Args:
|
||||
scene: 分镜场景描述
|
||||
required_duration: 所需时长(秒)
|
||||
|
||||
Returns:
|
||||
匹配到的素材 {url, duration},无匹配返回 None
|
||||
"""
|
||||
for keyword, slug in _keywords.items():
|
||||
if keyword in scene:
|
||||
candidates = [
|
||||
m for m in _materials.get(slug, [])
|
||||
if m["duration"] >= required_duration
|
||||
]
|
||||
if candidates:
|
||||
return random.choice(candidates)
|
||||
return None
|
||||
@@ -0,0 +1,635 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"keywords": {
|
||||
"吊顶": "ceiling",
|
||||
"天花": "ceiling",
|
||||
"水电": "plumbing",
|
||||
"水管": "plumbing",
|
||||
"油漆": "paint",
|
||||
"涂料": "paint",
|
||||
"刷漆": "paint",
|
||||
"完工": "final",
|
||||
"竣工": "final",
|
||||
"交付": "final"
|
||||
},
|
||||
"materials": {
|
||||
"ceiling": [
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/ceiling/ceiling_5s_c1e06c14.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/ceiling/ceiling_6s_4091bf65.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/ceiling/ceiling_6s_78fdb4d1.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/ceiling/ceiling_7s_52ffb6e9.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/ceiling/ceiling_8s_14ce7f1d.mp4"
|
||||
}
|
||||
],
|
||||
"paint": [
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/paint/paint_4s_7981c90b.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/paint/paint_5s_94e1a99e.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/paint/paint_5s_bec25ff4.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/paint/paint_6s_178e2b25.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/paint/paint_6s_26cc917c.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/paint/paint_7s_7a16fb72.mp4"
|
||||
}
|
||||
],
|
||||
"tile": [
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/tile/tile_4s_7be39898.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/tile/tile_4s_aeb1343d.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/tile/tile_5s_4c1e25dc.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/tile/tile_5s_b26b8cae.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/tile/tile_5s_fe2a8645.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/tile/tile_6s_55ffa0ff.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/tile/tile_6s_a2447a54.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/tile/tile_7s_95b87885.mp4"
|
||||
}
|
||||
],
|
||||
"waterproof": [
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_10s_a2b0f6da.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_11s_eaf4b9f0.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_5s_22f5e19b.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_5s_35498a2a.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_5s_6cbb95dc.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_5s_aa110132.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_5s_da3a9f8d.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_6s_32c90edb.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_6s_51d60412.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_6s_59cbfabd.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_6s_88d43e86.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_6s_9a6c1e20.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_7s_4be2c8b3.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_7s_efb40fd3.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_8s_13fc8a2a.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_8s_c816798f.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/waterproof/waterproof_9s_5c3820be.mp4"
|
||||
}
|
||||
],
|
||||
"final": [
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/final/final_10s_40b78665.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/final/final_11s_7c8c6833.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/final/final_4s_5ee06c87.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/final/final_4s_a8994032.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/final/final_5s_98b64716.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/final/final_6s_83e76197.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/final/final_7s_109bde47.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/final/final_7s_8b9df21b.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/final/final_7s_ee3be316.mp4"
|
||||
}
|
||||
],
|
||||
"plumbing": [
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_10s_a23f8fcb.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_11s_8cad4c63.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_3s_014d4b99.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_3s_26c96bb3.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_3s_88f3c2ff.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_3s_8f9e2fd1.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_3s_917e73d2.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_3s_a21a93c2.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_3s_b41346c9.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_3s_b6c5d8d5.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_3s_c83e401f.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_3s_edc3ed94.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_06c176f7.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_0d8188b0.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_1d024051.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_26252c4f.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_289d05b9.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_291ff9cd.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_2a24e5dd.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_2ea437ff.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_30204ab3.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_3279abb0.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_370db89d.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_3fa42431.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_46a47e19.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_4b6e8a71.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_4db3ad9d.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_5670036a.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_5de6f9c7.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_635ceca4.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_66d70c58.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_6ac4e162.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_6f61c1d7.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_77a83b95.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_80f8c4db.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_8782b24d.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_8a4aac19.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_9193c60f.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_923da0a5.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_92c20623.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_991614c2.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_a5a8f8e9.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_abac94a2.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_adda5387.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_b2386645.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_c011f332.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_d7977183.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_daf3eb45.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_ddf27707.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_e8224a6a.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_edf6cd59.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_eed46b34.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_4s_f01dbb9a.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_01547dc3.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_01a8ac16.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_03c341ba.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_03fc74f5.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_10b4f6d7.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_12d6cc7f.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_17492b31.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_192bd9cc.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_1db4fcc0.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_1e8fabdb.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_1ebe0150.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_22532b8d.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_239aa4e0.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_2461447a.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_29b29710.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_2b144bbe.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_4ac4f57e.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_4e8a4605.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_50a842d5.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_58f310b5.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_5a6d3324.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_7afd5931.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_80d28904.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_845aaeb5.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_8920d53d.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_91f27b4d.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_924538a9.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_964c51f3.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_a76f5d31.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_a7afa965.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_aa9a3927.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_aac7da24.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_aafcc59d.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_b56deb39.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_b7150433.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_b920788e.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_ba04551e.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_bbb8dc91.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_bf0f4247.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_c02abcad.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_c06f8b5c.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_cb24fc27.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_cbaa1936.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_ccec7599.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_ddcadc8c.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_e0da2b38.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_fcf594b4.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_5s_ff920a11.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_06f77a48.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_0a814b44.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_0b62bfaa.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_1850465b.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_24db5614.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_41e2f984.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_4dcfba99.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_501f7797.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_54090579.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_548c3105.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_5683347b.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_7d3db3d5.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_7e30771b.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_801e5229.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_8dc61b6c.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_8ef50b5a.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_b39a845c.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_b456e9ea.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_b570d306.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_b8952314.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_bf9443da.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_cd17be55.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_de6b43ec.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_6s_dfb8c797.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_0347af3b.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_176e9cb9.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_22a74e9e.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_2b31aa82.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_2e62e3c0.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_3e6c3f0e.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_696efd19.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_7e1a3879.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_867c9942.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_95a93892.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_9ef1fc68.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_a9fb2286.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_ca1063e6.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_d73638e7.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_e0b10567.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_ea506fe9.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_7s_f0d979ba.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_0fe1953c.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_1f04e5f3.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_21b61c48.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_67a52a55.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_69833536.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_705db3bf.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_ab98331b.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_ae8c2c29.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_be9d5579.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_c4ad7c9f.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_d9805d78.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_8s_e77c4bed.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_9s_47be1915.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_9s_4c1e542f.mp4"
|
||||
},
|
||||
{
|
||||
"url": "https://media.liche.cn/meijiaka-zj/material/plumbing/plumbing_9s_5e45c9e5.mp4"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@ services:
|
||||
environment:
|
||||
- ENV=development
|
||||
- DEBUG=true
|
||||
- DATABASE_URL=postgresql+asyncpg://postgres:postgres@db:5432/meijiaka_zj
|
||||
- REDIS_HOST=redis
|
||||
- DATABASE_URL=postgresql+asyncpg://postgres:postgres@meijiaka-db:5432/meijiaka_zj
|
||||
- REDIS_HOST=meijiaka-redis
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_DB=1
|
||||
- SECRET_KEY=dev-secret-key-change-in-production
|
||||
@@ -37,8 +37,8 @@ services:
|
||||
environment:
|
||||
- ENV=development
|
||||
- DEBUG=true
|
||||
- DATABASE_URL=postgresql+asyncpg://postgres:postgres@db:5432/meijiaka_zj
|
||||
- REDIS_HOST=redis
|
||||
- DATABASE_URL=postgresql+asyncpg://postgres:postgres@meijiaka-db:5432/meijiaka_zj
|
||||
- REDIS_HOST=meijiaka-redis
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_DB=1
|
||||
- SECRET_KEY=dev-secret-key-change-in-production
|
||||
|
||||
Reference in New Issue
Block a user