This commit is contained in:
liubiren 2026-01-14 21:56:55 +08:00
parent 9781c8d7f2
commit 5ff511f898
4 changed files with 133 additions and 94 deletions

View File

@ -21,8 +21,6 @@ class JianYingDraft:
6将草稿保存至剪映草稿文件夹内
"""
# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments
def __init__(
self,
drafts_folder: pyJianYingDraft.DraftFolder,
@ -122,7 +120,6 @@ class JianYingDraft:
text_segment.add_bubble(**bubble)
# 添加花字
# pylint: disable=line-too-long
# 将花字保存预设后在C:/Users/admin/AppData/Local/JianyingPro/User Data/Presets/Text_V2/预设文本?.textpreset获取花字resource_id
if effect:
text_segment.add_effect(**effect)
@ -319,7 +316,6 @@ class JianYingDraft:
)
# 构建贴纸
# pylint: disable=line-too-long
# 将贴纸保存为我的预设后在C:\Users\admin\AppData\Local\JianyingPro\User Data\Presets\Combination\Presets\我的预设?\preset_draft获取
sticker_segment = pyJianYingDraft.StickerSegment(
resource_id=resource_id,
@ -350,7 +346,7 @@ class JianYingDraft:
rate: str = "+25%",
volume: str = "+0%",
font: Optional[str] = None,
style: Optional[Dict[str, Any]] = None,
style: Optional[Dict[str, Any]] = {"size": 12.0, "align": "center"},
clip_settings: Optional[Dict[str, Any]] = None,
effect: Optional[Dict[str, Any]] = None,
):
@ -402,7 +398,7 @@ class JianYingDraft:
**(style or {}),
},
clip_settings={
"transform_y": -0.75,
"transform_y": -0.6,
**(clip_settings or {}),
},
effect=effect,

View File

@ -3,15 +3,19 @@
导出草稿模块
"""
from copy import deepcopy
import json
from pathlib import Path
import random
import re
import subprocess
import time
from pathlib import Path
from typing import Any, Dict, Optional
import pyJianYingDraft
import win32con
import win32gui
from draft import JianYingDraft
@ -25,8 +29,6 @@ class JianYingExport:
3导出草稿
"""
# pylint: disable=too-many-arguments
# pylint: disable=too-many-positional-arguments
def __init__(
self,
materials_folder_path: str,
@ -72,7 +74,7 @@ class JianYingExport:
self.exports_folder_path = Path(
self.materials_folder_path.as_posix().replace("materials", "exports")
)
self.exports_folder_path.mkdir() # 若导出文件夹存在则抛出异常,需手动处理
# self.exports_folder_path.mkdir() # 若导出文件夹存在则抛出异常,需手动处理
self.materials = {}
# 初始化素材文件夹内所有素材
@ -106,6 +108,9 @@ class JianYingExport:
{"size": 10.0},
{"size": 11.0},
], # 字体样式
"keywords": [
"瑞幸",
], # 关键词
"effect": [
{"effect_id": "7127561998556089631"},
{"effect_id": "7166467215410187552"},
@ -120,71 +125,13 @@ class JianYingExport:
], # 花字设置
}, # 添加字幕工作配置
"add_background_video": {
"track_name": ["background_video"],
"material_path": self.materials["background_video_material_path"],
"volume": [0.3, 0.4, 0.5],
"clip_settings": [
None,
{
"transform_x": 0.1,
},
{
"transform_x": 0.2,
},
{
"transform_x": -0.1,
},
{
"transform_x": -0.2,
},
{
"transform_y": 0.1,
},
{
"transform_y": 0.2,
},
{
"transform_y": -0.1,
},
{
"transform_y": -0.2,
},
{
"transform_x": 0.1,
"transform_y": 0.1,
},
{
"transform_x": 0.1,
"transform_y": -0.1,
},
{
"transform_x": -0.1,
"transform_y": 0.1,
},
{
"transform_x": -0.1,
"transform_y": -0.1,
},
{
"transform_x": 0.2,
"transform_y": 0.2,
},
{
"transform_x": 0.2,
"transform_y": -0.2,
},
{
"transform_x": -0.2,
"transform_y": 0.2,
},
{
"transform_x": -0.2,
"transform_y": -0.2,
},
], # 图像调节设置
}, # 添加背景视频工作配置
"add_logo": {
"track_name": ["logo"],
"material_path": self.materials["logo_material_path"],
"clip_settings": [
{
@ -220,19 +167,18 @@ class JianYingExport:
],
}, # 添加标识工作配置
"add_statement": {
"track_name": ["statement"],
"text": self.materials["statement_text"],
"style": [
{"size": 5.0, "align": 1, "vertical": True},
{"size": 6.0, "align": 1, "vertical": True},
{"size": 7.0, "align": 1, "vertical": True},
{"size": 8.0, "align": 1, "vertical": True},
], # 文本样式
"border": [
{"width": 35.0},
{"width": 40.0},
{"width": 44.0},
{"width": 45.0},
{"width": 50.0},
{"width": 55.0},
{"width": 60.0},
], # 描边宽度
"clip_settings": [
{
@ -247,7 +193,6 @@ class JianYingExport:
], # 图像调节设置
}, # 添加声明工作配置
"add_sticker1": {
"track_name": ["sticker1"],
"resource_id": [
"7110124379568098568",
"7019687632804334861",
@ -286,7 +231,6 @@ class JianYingExport:
], # 图像调节设置
}, # 添加贴纸工作配置1不包含箭头类
"add_sticker2": {
"track_name": ["sticker2"],
"resource_id": [
"7143078914989018379",
"7142870400358255905",
@ -370,8 +314,9 @@ class JianYingExport:
导出草稿
:param batch_draft_counts: 每批次导出草稿数
"""
# 按照工作流和工作配置拼接素材,生成草稿
self._generate()
# 按照工作流和工作配置拼接素材,批量生成草稿
self._generate_drafts()
exit()
# 批次导出
for batch_start in range(0, self.draft_counts, batch_draft_counts):
@ -409,11 +354,11 @@ class JianYingExport:
self.drafts_folder.remove(draft_name=draft_name)
time.sleep(2)
def _generate(
def _generate_drafts(
self,
) -> None:
"""
按照工作流和工作配置拼接素材生成草稿
按照工作流和工作配置拼接素材批量生成草稿
:return:
"""
for idx in range(self.draft_counts):
@ -434,27 +379,27 @@ class JianYingExport:
match work:
case "add_subtitles":
print("-> 正在添加字幕...", end="")
draft.add_subtitles(**self._random(work=work))
draft.add_subtitles(**self._get_parameters(work=work))
print("已完成")
# 添加背景视频
case "add_background_video":
print("-> 正在添加背景视频...", end="")
draft.add_video_segment(**self._random(work=work))
draft.add_video_segment(**self._get_parameters(work=work))
print("已完成")
# 添加标识
case "add_logo":
print("-> 正在添加标识...", end="")
draft.add_video_segment(**self._random(work=work))
draft.add_video_segment(**self._get_parameters(work=work))
print("已完成")
# 添加声明
case "add_statement":
print("-> 正在添加声明...", end="")
draft.add_text_segment(**self._random(work=work))
draft.add_text_segment(**self._get_parameters(work=work))
print("已完成")
# 添加贴纸
case _ if work.startswith("add_sticker"):
print("-> 正在添加贴纸...", end="")
draft.add_sticker(**self._random(work=work))
draft.add_sticker(**self._get_parameters(work=work))
print("已完成")
# 将草稿保存至剪映草稿文件夹内
case "save":
@ -462,6 +407,10 @@ class JianYingExport:
draft.save()
print("已完成")
# 高亮关键词
self._highlight_keywords(draft_name=draft_name)
exit()
self.draft_names.append(draft_name)
print("已完成")
@ -470,18 +419,110 @@ class JianYingExport:
# 就所有草稿名称倒叙排序排序
self.draft_names.sort(reverse=True)
def _random(
def _get_parameters(
self,
work: str,
) -> Dict[str, Any]:
"""
随机化工作配置项
获取工作配置项
:param work: 工作包括添加字幕添加背景视频添加标识添加声明和添加贴纸
:return: 工作配置
"""
return {
parameters = {
key: random.choice(value) for key, value in self.configuration[work].items()
}
} # TODO: 考虑融合贝叶斯优化
if work == "add_subtitles":
parameters.pop("keywords")
# 就除添加字幕其它工作添加轨道名称
if work != "add_subtitles" and (
match := re.search(r"_(?P<track_name>.+)", work)
):
parameters["track_name"] = match.group("track_name")
return parameters
def _highlight_keywords(
self,
draft_name: str,
) -> None:
"""
高亮关键词
:param draft_name: 草稿名称
:return:
"""
time.sleep(2)
# 草稿内容路径
draft_content_path = self.drafts_folder_path / draft_name / "draft_content.json"
with open(
file=draft_content_path,
mode="r",
encoding="utf-8",
) as file:
draft_content = json.load(file)
# 字幕文本轨道所有文本片段的素材标识
material_ids = [
segment["material_id"]
for track in draft_content["tracks"]
if track["name"] == "subtitles(text)"
for segment in track["segments"]
]
# 遍历所有文本素材
for idx, material in enumerate(draft_content["materials"]["texts"]):
if material["id"] in material_ids:
# 素材内容
content = json.loads(s=material["content"])
# 素材文本
text = content["text"]
# 遍历关键词
for keyword in self.configuration["add_subtitles"]["keywords"]:
if match := next(re.finditer(pattern=keyword, string=text), None):
assert len(styles := content["styles"]) == 1, "样式设置数不为1"
# 根据关键词将文本拆分为三段,分别为前段、中段和后段样式。其中前段和后段样式无花字设置,中段样式有花字设置
middle_style = styles[0]
style = {
key: value
for key, value in middle_style.items()
if key != "effectStyle"
}
front_style = deepcopy(style)
rear_style = deepcopy(style)
# 将前段样式中终止位置设置为关键词起始位置
front_style["range"] = [0, match.start()]
# 将中段样式中起始和终止位置设置为关键词起始和终止位置
middle_style["range"] = [match.start(), match.end()]
# 调整字号
middle_style["size"] += 3
if match.end() != len(text):
# 将后段样式中起始位置设置为关键词终止位置
rear_style["range"] = [match.end(), len(text)]
styles = [front_style, middle_style, rear_style]
else:
styles = [front_style, middle_style]
draft_content["materials"]["texts"][idx]["content"] = (
json.dumps(
obj={
"styles": [front_style, middle_style, rear_style],
"text": text,
},
ensure_ascii=False,
)
)
with open(
file=draft_content_path,
mode="w",
encoding="utf-8",
) as file:
file.write(json.dumps(obj=draft_content, ensure_ascii=False, indent=4))
def _start_process(self, timeout: int = 60) -> None:
"""
@ -527,12 +568,10 @@ class JianYingExport:
window_handle = self._locate_window()
if window_handle is not None:
# 请求关闭剪映程序窗口
# pylint: disable=c-extension-no-member
win32gui.SendMessage(window_handle, win32con.WM_CLOSE, 0, 0)
start_time = time.time()
while time.time() - start_time < timeout:
# pylint: disable=c-extension-no-member
if not win32gui.IsWindow(window_handle):
print("已关闭剪映专业版进程")
return
@ -559,16 +598,17 @@ class JianYingExport:
# 初始化窗口句柄
nonlocal window_handle
# 获取窗口标题
# pylint: disable=c-extension-no-member
window_text = win32gui.GetWindowText(handle)
# 检查窗口是否可见且窗口标题为剪映专业版
# pylint: disable=c-extension-no-member
if win32gui.IsWindowVisible(handle) and window_text == "剪映专业版":
if (
win32gui.IsWindow(handle)
and win32gui.IsWindowVisible(handle)
and window_text == "剪映专业版"
):
window_handle = handle
return False
return True
# 遍历所有顶层窗口
# pylint: disable=c-extension-no-member
win32gui.EnumWindows(callback, None)
return window_handle

View File

@ -123,6 +123,7 @@ def image_classify(image_index: int, image_path: Path, dossier: Dict[str, Any])
"image_guid": image_guid, # 影像件唯一标识
"image_base64": image_base64, # 影像件BASE64编码
"image_type": image_type, # 影像件类型
"image_classified": "", # 影像件是否已分类
} # 影像件编号作为键名

View File

@ -406,6 +406,7 @@
<th>影像件编号</th>
<th>影像件路径</th>
<th>影像件类型</th>
<th>已分类</th>
<th>已识别</th>
</tr>
</thead>
@ -415,6 +416,7 @@
<td>{{ image_index }}</td>
<td>{{ image["image_name"] }}</td>
<td>{{ image["image_type"] }}</td>
<td>{{ image["image_classified"] }}</td>
<td>{{ image["image_recognized"] }}</td>
</tr>
{% endfor %}
@ -425,7 +427,7 @@
<h2>赔案层</h2>
<div class="card-container">
<div class="card">
<h3>出险人(被保险人)信息</h3>
<h3>出险人(被保险人)信息</h3>
<div class="info-grid">
<div class="info-item">
<div class="info-label">姓名</div>