#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
根据字幕图片和双语时间生成完整视频流
用法: python generate_bilingual_video.py <adid>
"""

import os
import sys
import sqlite3
import subprocess
import glob
import tempfile

from generate_bilingual_video import make_bili_vd

def get_subtitles(adid, db_path):
    """
    从数据库获取字幕信息
    """
    import inspect
    func_name = inspect.currentframe().f_code.co_name
    line_no = inspect.currentframe().f_lineno
    
    conn = None
    try:
        conn = sqlite3.connect(db_path, timeout=10.0)
        cursor = conn.cursor()
        
        cursor.execute("""
            SELECT idx, start, end, cn, en FROM srts 
            WHERE adid = ? 
            ORDER BY idx
        """, (adid,))
        
        subtitles = []
        for row in cursor.fetchall():
            idx, start, end, cn, en = row
            # 解析时间格式
            start_ms = int(start)
            end_ms = int(end)
            subtitles.append((idx, start_ms, end_ms, cn, en))
        
        return subtitles
    except Exception as e:
        import traceback
        print(f"错误 [函数: {func_name}, 行号: {line_no}]: 操作失败: {e}")
        traceback.print_exc()
        return []
    finally:
        if conn:
            conn.close()


def get_adname(adid, db_path):
    """
    从数据库获取adname
    """
    import inspect
    func_name = inspect.currentframe().f_code.co_name
    line_no = inspect.currentframe().f_lineno
    
    conn = None
    try:
        conn = sqlite3.connect(db_path, timeout=10.0)
        cursor = conn.cursor()
        
        cursor.execute("SELECT DISTINCT adname FROM srts WHERE adid = ? LIMIT 1", (adid,))
        result = cursor.fetchone()
        
        if result:
            return result[0]
        return f"adid_{adid}"
    except Exception as e:
        import traceback
        print(f"错误 [函数: {func_name}, 行号: {line_no}]: 操作失败: {e}")
        traceback.print_exc()
        return f"adid_{adid}"
    finally:
        if conn:
            conn.close()


def get_bilingual_time(adid):
    """
    读取双语时间信息
    """
    # 配置
    db_path = r'\\ll\D\xtrssvjj\db\dpd.db'
    
    # 获取adname
    adname = get_adname(adid, db_path)
    
    # 目录路径
    cn_audio_dir = f"{adname}_cn_audio"
    en_tts_dir = os.path.join(r'\\ll\D\xtrssvjj', 'tts', adname)
    
    # 获取字幕
    subtitles = get_subtitles(adid, db_path)
    
    # 音频文件路径
    audio_file = os.path.join(r'\\ll\D\xtrssvjj', f"{adname}.mp3")
    
    # 获取音频文件总长度
    def get_file_duration(file_path):
        cmd = ["ffprobe", "-v", "quiet", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", file_path]
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode == 0:
            return int(float(result.stdout.strip()) * 1000)
        return 0
    
    audio_duration = get_file_duration(audio_file)
    
    # 计算每句的startpos、endpos、addstart、addend
    bilingual_times = []
    for i, (idx, start, end, cn, en) in enumerate(subtitles):
        prevend = subtitles[i-1][2] if i > 0 else 0
        startgap = start - prevend if i > 0 else 0
        
        if i < len(subtitles)-1:
            nextstart = subtitles[i+1][1]
            endgap = nextstart - end
        else:
            # 最后一句的nextstart为音频文件的实际总长度
            nextstart = audio_duration
            endgap = nextstart - end if audio_duration > end else 0
        
        # 计算startpos和endpos
        # 第一句的startpos固定为0
        if i == 0:
            startpos = 0
        else:
            startpos = (prevend + start) // 2
        
        # 最后一句的endpos为视频的最后位置(总长度-1)
        if i == len(subtitles)-1:
            endpos = audio_duration - 1
        else:
            endpos = (end + nextstart) // 2
        
        # 计算addstart值：第一句addstart=0，后面的用400-(start-startpos)
        if i == 0:
            addstart = 0
        else:
            addstart = 400 - (start - startpos)
            if addstart <= 0:
                addstart = 0
        
        # 计算addend值：最后一句addend=0，其他用400-(endpos-end)
        if i == len(subtitles)-1:
            addend = 0
        else:
            addend = 400 - (endpos - end)
            if addend <= 0:
                addend = 0
        
        # 获取中文音频长度
        cn_audio_file = os.path.join(cn_audio_dir, f"seg{idx:03d}-{startpos}-{endpos}-*.mp3")
        cn_files = glob.glob(cn_audio_file)
        cn_duration = 0
        if cn_files:
            cn_duration = get_file_duration(cn_files[0])
        
        # 获取英文TTS长度 - 只使用网络共享位置的TTS文件
        en_tts_pattern = os.path.join(en_tts_dir, f"*-{idx:04d}.mp3")
        en_files = glob.glob(en_tts_pattern)
        
        en_duration = 0
        if en_files:
            # 打印使用的网络TTS文件路径
            print(f"使用网络TTS文件: {en_files[0]}")
            # 计算调整语速后的TTS长度（原长度 / 0.7）
            original_duration = get_file_duration(en_files[0])
            en_duration = original_duration / 0.7
        
        # 计算双语总时间
        bilingual_time = addstart + cn_duration + addend + en_duration
        
        bilingual_times.append((idx, bilingual_time))
    
    return bilingual_times
def calccoverimgfilename(filemain):
    cover_dir = r"y:\xtrssvjj"
    output_path = f"mp4forpub/{filemain}_platform_ready.mp4"
    
    # 1. 搜寻封面
    search_pattern = os.path.join(cover_dir, f"{filemain}*.jpg")
    print('cover img:',search_pattern)
    found_covers = glob.glob(search_pattern)
    if not found_covers:
        print("❌ 未找到封面图")
        return    
    image_path = max(found_covers, key=os.path.getmtime)
    return image_path
import subprocess
from pathlib import Path

def generate_cover_clip(image_file, duration_sec, coverfile):
    # 1. 路径标准化：resolve() 解决相对路径问题，str() 转为标准字符串
    img_path = str(Path(image_file).resolve())
    out_path = str(Path(coverfile).resolve())

    # 2. 构建命令
    cmd = [
        "ffmpeg", "-y", "-hide_banner",
        "-loop", "1",
        "-i", f"file:{img_path}",      # 优雅点1：显式使用 file: 协议，规避 # 等字符干扰
        "-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2,format=yuv420p", # 优雅点2：强制偶数化并设置像素格式
        "-c:v", "libx264",
        "-tune", "stillimage",
        "-t", str(duration_sec),
        "-c:a", "aac",
        "-b:a", "192k",
        "-f", "lavfi", "-i", "anullsrc=channel_layout=stereo:sample_rate=44100", # 补齐静音轨防止合成报错
        "-shortest",
        out_path
    ]

    try:
        # 优雅点3：使用 errors='ignore' 避免 ffmpeg 输出中的非 UTF-8 字符导致 Python 崩溃
        result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8', errors='ignore')
        
        if result.returncode == 0:
            print(f"✅ 生成成功: {coverfile}")
        else:
            # 如果报错，打印出完整的命令和错误信息方便调试
            print(f"❌ FFmpeg 失败!")
            print(f"错误详情: {result.stderr}")
            print(f"尝试执行的完整命令: {' '.join(cmd)}")
            
    except Exception as e:
        print(f"💥 脚本异常: {e}")

# 调用示例
# generate_cover_clip("台积电有多厉害？_xWT158.jpg", 0.1, "cover_fragment.mp4")

import subprocess
from pathlib import Path

def generate_cover_clip(image_file, duration_sec, coverfile):
    img_path = str(Path(image_file).resolve())
    out_path = str(Path(coverfile).resolve())

    # 核心逻辑：
    # 1. 所有的 -i (输入) 放在前面
    # 2. 所有的处理参数 (-vf, -c:v, -t) 放在输入之后
    cmd = [
        "ffmpeg", "-y", "-hide_banner",
        "-loop", "1", "-i", f"file:{img_path}",      # 输入1：图片
        "-f", "lavfi", "-i", "anullsrc=channel_layout=stereo:sample_rate=44100", # 输入2：静音
        "-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2,format=yuv420p", # 滤镜：确保偶数并对齐格式
        "-c:v", "libx264",
        "-tune", "stillimage",
        "-c:a", "aac",
        "-b:a", "192k",
        "-t", str(duration_sec),                      # 放在这里确保对全局生效
        "-shortest",                                  # 确保音频和视频长度对齐
        out_path                                      # 输出文件
    ]

    try:
        # 使用 errors='ignore' 防止 stderr 里的特殊字符让 Python 崩溃
        result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8', errors='ignore')
        
        if result.returncode == 0:
            print(f"✅ 生成成功: {coverfile}")
        else:
            print(f"❌ FFmpeg 失败!")
            print(f"错误详情:\n{result.stderr}")
    except Exception as e:
        print(f"💥 脚本异常: {e}")

# 调用示例
# generate_cover_clip("台积电有多厉害？_xWT158.jpg", 1, "cover.mp4")

def make_cover_video(adid):
    """
    生成完整的视频流
    """
    # 配置
    db_path = r'\\ll\D\xtrssvjj\db\dpd.db'
    
    # 获取adname
    adname = get_adname(adid, db_path)
    print(f"adname: {adname}")
    image_file=calccoverimgfilename(adname)        
    if not image_file:
        return
    # 转换时长为秒
    duration_sec = 1
    
    # 输出文件名
    coverfile = "cover.mp4"
    generate_cover_clip(image_file,1,coverfile)

    # 生成视频片段
    cmd = [
        "ffmpeg", "-y",
        "-loop", "1",
        "-i", image_file,
        "-c:v", "libx264",
        "-tune", "stillimage",
        "-c:a", "aac",
        "-b:a", "192k",
        "-pix_fmt", "yuv420p",
        "-t", str(duration_sec),
        "-shortest",
        coverfile
    ]    
    try:
        # result=subprocess.run(cmd, check=True) 
        result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
        if result.returncode == 0:
            print(f"✅ 处理完成！cover mp4: {coverfile}")
            return
        else:
            print(f"❌ 出错了：{result.stderr}")
    except Exception as e:
        print(f"💥 崩溃: {e}")
    
    if os.path.exists(coverfile):
        return True
def main():
    """
    主函数
    """
    # if len(sys.argv) != 2:
    #     print("用法: python generate_bilingual_video.py <adid>")
    #     print("示例: python generate_bilingual_video.py 8496")
    #     sys.exit(1)
    
    try:
        adid = int(sys.argv[1])
    except ValueError:
        print("错误：adid必须是数字")
        # sys.exit(1)
        adid=280372
    except Exception as ex:
        print("xxx",ex)
        # sys.exit(1)
        adid=280377
    print(f"=== 双语视频流生成工具 ===")
    print(os.path.basename(__file__))    
    print(f"adid: {adid}")
    
    # success = make_cover_video(adid)
    success = make_bili_vd(adid)
    
    if success:
        print("\n视频流生成完成！")
    else:
        print("\n视频流生成失败！")
        sys.exit(1)


if __name__ == "__main__":
    main()
