# utils/tab2_search_video.py import streamlit as st import os from pathlib import Path from utils.helpers import analyze_ass_for_keywords, search_pixabay_videos, search_pexels_videos from utils.helpers import display_operation_status @st.fragment def render_tab(project,callbacks): """一個用於從多個來源搜尋並下載影片的獨立UI片段。""" display_operation_status paths = project.paths st.header("從線上圖庫搜尋影片素材") pixabay_api_key = st.secrets.get("PIXABAY_API_KEY") pexels_api_key = st.secrets.get("PEXELS_API_KEY") if not pixabay_api_key and not pexels_api_key: st.warning("請至少在 Streamlit secrets 中設定 `PIXABAY_API_KEY` 或 `PEXELS_API_KEY` 以使用此功能。") return st.subheader("搜尋影片") # 【新增】影片來源選擇 available_sources = [] if pixabay_api_key: available_sources.append("Pixabay") if pexels_api_key: available_sources.append("Pexels") if not available_sources: st.session_state.operation_status = { "success": False, "message": "沒有可用的影片來源 API 金鑰。" } return source_choice = st.radio( "選擇影片來源:", options=available_sources, horizontal=True, key="video_source_choice" ) keywords = analyze_ass_for_keywords(paths) default_query = keywords[0] if keywords else "" with st.form(key="search_form"): col1, col2 = st.columns([4, 1]) with col1: st.text_input( "Search Videos", value=default_query, key="search_query_input", placeholder="輸入關鍵字後按 Enter 或點擊右側按鈕搜尋", label_visibility="collapsed" ) with col2: submitted = st.form_submit_button("🔍 搜尋影片", use_container_width=True) if submitted: with st.spinner("正在搜尋並過濾影片..."): query = st.session_state.get("search_query_input", "") # 【修改】根據選擇呼叫對應的 API if source_choice == "Pixabay": success, message, results = search_pixabay_videos(pixabay_api_key, query) elif source_choice == "Pexels": success, message, results = search_pexels_videos(pexels_api_key, query) else: success, message, results = False, "未知的影片來源", [] st.session_state.operation_status = {"success": success, "message": message, "source": "search_videos"} # --- 【修改】資料標準化 --- standardized_results = [] if success and results: if source_choice == "Pixabay": for v in results: try: standardized_results.append({ 'id': f"pixabay-{v['id']}", 'thumbnail_url': v['videos']['tiny']['thumbnail'], 'video_url': v['videos']['large']['url'], 'preview_url': v['videos']['tiny']['url'], 'width': v['videos']['large']['width'], 'height': v['videos']['large']['height'] }) except KeyError: continue elif source_choice == "Pexels": for v in results: try: # 尋找合適的影片檔案連結 video_link_hd = next((f['link'] for f in v['video_files'] if f.get('quality') == 'hd'), None) video_link_sd = next((f['link'] for f in v['video_files'] if f.get('quality') == 'sd'), None) # 優先使用 HD 畫質,若無則用 SD,再沒有就用第一個 final_video_url = video_link_hd or video_link_sd or v['video_files'][0]['link'] standardized_results.append({ 'id': f"pexels-{v['id']}", 'thumbnail_url': v['image'], 'video_url': final_video_url, 'preview_url': video_link_sd or final_video_url, # 預覽用 SD 或更高畫質 'width': v['width'], 'height': v['height'] }) except (KeyError, IndexError): continue st.session_state.search_results = standardized_results st.session_state.selected_videos = {str(v['id']): {"url": v['video_url'], "selected": False} for v in standardized_results} st.session_state.active_preview_id = None if keywords and (keywords[1] or keywords[2]): st.caption(f"建議關鍵字: `{keywords[1]}` `{keywords[2]}`") st.divider() if st.session_state.search_results: st.subheader("選擇影片並下載") st.button("📥 下載選取的影片到專案素材庫", on_click=callbacks.callback_download_videos, args=(paths,), help="將下方勾選的影片下載至目前專案的 `output/temp_video` 資料夾,並自動循序命名。") num_cols = 5 cols = st.columns(num_cols) # 【修改】使用標準化後的結果進行渲染 for i, video in enumerate(st.session_state.search_results): with cols[i % num_cols]: with st.container(border=True): media_placeholder = st.empty() video_id_str = str(video['id']) if st.session_state.active_preview_id == video_id_str: media_placeholder.video(video['preview_url']) preview_button_text, preview_button_type = "⏹️ 停止預覽", "secondary" else: media_placeholder.image(video['thumbnail_url'], use_container_width=True) preview_button_text, preview_button_type = "▶️ 預覽", "primary" st.caption(f"ID: {video_id_str}") st.caption(f"尺寸: {video['width']}x{video['height']}") is_selected = st.checkbox("選取", key=f"select_{video_id_str}", value=st.session_state.selected_videos.get(video_id_str, {}).get('selected', False)) if video_id_str in st.session_state.selected_videos: st.session_state.selected_videos[video_id_str]['selected'] = is_selected st.button(preview_button_text, key=f"preview_{video_id_str}", on_click=callbacks.callback_toggle_preview, args=(video_id_str,), use_container_width=True, type=preview_button_type)