version 1
This commit is contained in:
124
ui_fragments/tab3_video_composition.py
Normal file
124
ui_fragments/tab3_video_composition.py
Normal file
@ -0,0 +1,124 @@
|
||||
|
||||
import streamlit as st
|
||||
from pathlib import Path
|
||||
from config import SHARED_ASSETS_DIR
|
||||
|
||||
@st.fragment
|
||||
def render_tab(project, callbacks):
|
||||
"""渲染「最終影片合成」標籤頁的 UI。"""
|
||||
|
||||
_render_video_management_section(project, callbacks)
|
||||
_render_shared_asset_uploader(callbacks)
|
||||
_render_shared_asset_selection(callbacks)
|
||||
|
||||
st.divider()
|
||||
|
||||
@st.fragment
|
||||
def _render_video_management_section(project, callbacks):
|
||||
"""
|
||||
一個私有的輔助函式,用於渲染影片管理的 UI 部分。
|
||||
"""
|
||||
with st.expander("🎬 管理專案影片素材", expanded=False):
|
||||
paths = project.paths
|
||||
output_dir = paths.get("output", Path("./output")) # 使用 .get 提供預設值
|
||||
video_files = []
|
||||
|
||||
if output_dir.exists():
|
||||
video_files = sorted(
|
||||
[f for f in output_dir.iterdir() if f.suffix.lower() in ['.mp4', '.mov']],
|
||||
key=lambda f: f.stat().st_mtime,
|
||||
reverse=True
|
||||
)
|
||||
|
||||
if not video_files:
|
||||
st.info("專案輸出資料夾 (`/output`) 中目前沒有影片檔。")
|
||||
else:
|
||||
st.markdown("勾選您想要刪除的影片,然後點擊下方的按鈕。")
|
||||
|
||||
st.checkbox(
|
||||
"全選/取消全選",
|
||||
key="select_all_videos",
|
||||
on_change=callbacks.toggle_all_video_checkboxes,
|
||||
args=(video_files,)
|
||||
)
|
||||
|
||||
for video_file in video_files:
|
||||
file_size_mb = video_file.stat().st_size / (1024 * 1024)
|
||||
st.checkbox(
|
||||
f"**{video_file.name}** ({file_size_mb:.2f} MB)",
|
||||
key=f"delete_cb_{video_file.name}"
|
||||
)
|
||||
|
||||
st.button(
|
||||
"🟥 確認刪除選取的影片",
|
||||
on_click=callbacks.delete_selected_videos,
|
||||
use_container_width=True,
|
||||
type="primary"
|
||||
)
|
||||
|
||||
def _render_shared_asset_selection(callbacks):
|
||||
"""
|
||||
一個私有的輔助函式,用於渲染共享素材選擇和上傳的 UI。
|
||||
"""
|
||||
st.subheader("步驟 3.2: 選擇共享影片素材")
|
||||
st.subheader("輔助工具")
|
||||
|
||||
|
||||
# 【改動 1】更健壯的檔案列表讀取方式
|
||||
try:
|
||||
shared_videos = [""] + sorted(
|
||||
[f.name for f in SHARED_ASSETS_DIR.glob('*') if f.suffix.lower() in ['.mp4', '.mov']]
|
||||
)
|
||||
except Exception as e:
|
||||
st.error(f"無法讀取共享素材庫 '{SHARED_ASSETS_DIR}': {e}")
|
||||
shared_videos = [""]
|
||||
|
||||
with st.container(border=True):
|
||||
st.markdown("##### 從共享素材庫中選擇影片")
|
||||
c1, c2 = st.columns(2)
|
||||
with c1:
|
||||
logo_selection = st.selectbox("選擇 Logo 影片:", shared_videos, key="logo_select")
|
||||
open_selection = st.selectbox("選擇開場影片:", shared_videos, key="open_select")
|
||||
with c2:
|
||||
end_selection = st.selectbox("選擇結尾影片:", shared_videos, key="end_select")
|
||||
|
||||
st.subheader("步驟 3.2: 執行最終影片合成")
|
||||
all_videos_selected = all([logo_selection, open_selection, end_selection])
|
||||
|
||||
if not all_videos_selected:
|
||||
st.info("請從上方的下拉選單中選擇所有 Logo、開場和結尾影片以啟用合成按鈕。")
|
||||
|
||||
|
||||
# 【核心改動】st.button 的呼叫現在非常簡潔
|
||||
st.button(
|
||||
"🎬 合成最終影片",
|
||||
on_click=callbacks.assemble_final_video,
|
||||
kwargs={
|
||||
# 只傳遞 UI 直接相關的、最少的資訊 (檔名)
|
||||
"logo_video_name": logo_selection,
|
||||
"open_video_name": open_selection,
|
||||
"end_video_name": end_selection
|
||||
},
|
||||
disabled=not all_videos_selected,
|
||||
use_container_width=True
|
||||
)
|
||||
|
||||
|
||||
# 將選擇的結果回傳給主函式
|
||||
return logo_selection, open_selection, end_selection
|
||||
|
||||
def _render_shared_asset_uploader(callbacks):
|
||||
"""一個私有的輔助函式,用於渲染共享素材上傳工具。"""
|
||||
with st.expander("📂 管理與上傳共享素材", expanded=False):
|
||||
st.markdown("這裡上傳的影片將存入 `shared_assets` 公共資料夾,可供所有專案重複使用。")
|
||||
|
||||
st.file_uploader(
|
||||
"上傳新的影片到共享素材庫",
|
||||
type=["mp4", "mov"],
|
||||
accept_multiple_files=True,
|
||||
label_visibility="collapsed",
|
||||
key="shared_video_uploader",
|
||||
on_change=callbacks.upload_shared_videos
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user