#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
截取中文音频并拼接双语音频
用法: python joinbiliad.py <adid>
"""

import os
import sys
import sqlite3
import subprocess
import shutil
import tempfile
import glob
from datetime import datetime

import requests

def get_file_duration(file_path):
    """
    获取音频文件时长（毫秒）
    """
    # cmd = ["ffprobe", "-f","mp3","-v", "quiet", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", "-i",f"file:{file_path}"]
    cmd = ["ffprobe","-v", "quiet", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", "-i",f"file:{file_path}"]
    result = subprocess.run(cmd, capture_output=True, text=True)
    # print(file_path)
    # print(result.stdout)
    if result.returncode:
        return 0
    try:
        return int(float(result.stdout.strip()) * 1000)
    except Exception as ex:
        print('xxx',ex)
        print('ffprobe file=',file_path)
        print(" stdout:",result.stdout)
        return 0
def get_subtitles(adid, db_path):
    """
    从数据库获取字幕信息
    """
    import inspect
    func_name = inspect.currentframe().f_code.co_name
    line_no = inspect.currentframe().f_lineno    
    conn = None
    cursor = None
    try:
        print(1)
        conn = sqlite3.connect(db_path, timeout=60.0)
        try:
            conn.execute("PRAGMA journal_mode=WAL;")            
            # 优化数据库参数，减少锁定
            conn.execute('PRAGMA synchronous=NORMAL')
            conn.execute('PRAGMA cache_size=-64000')
        except Exception as e:
            conn.close()
            raise
        cursor = conn.cursor()        
        cursor.execute("""
            SELECT idx, start, end, cn, en FROM srts 
            WHERE adid = ? 
            ORDER BY idx
        """, (adid,))
        print(2)
        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))        
        print(3,len(subtitles))
        return subtitles
    except Exception as e:
        import traceback
        print(f"错误 [函数: {func_name}, 行号: {line_no}]: 操作失败: {e}")
        traceback.print_exc()
        return []
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()
def get_subtitles(adid,db_path):
    try:
        url=f'http://ll:899/api/reqsrts4makebilivd/{adid}'
        resp=requests.get(url)
        qrsrts=resp.json()
        return qrsrts
    except Exception as e:
        import traceback
        print(f"xxx 操作失败: {e}")
        traceback.print_exc()
    return []
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=60.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 generate_silence(duration_ms, output_path):
    """
    生成指定长度的静音音频
    """
    duration_sec = duration_ms / 1000
    cmd = [
        "ffmpeg", "-y",
        "-f", "lavfi",
        "-i", "anullsrc=channel_layout=stereo:sample_rate=44100",
        "-t", str(duration_sec),
        "-acodec", "libmp3lame",
        output_path
    ]
    subprocess.run(cmd, capture_output=True)


def extract_and_combine(adid,adname):
    """
    截取中文音频并拼接双语音频
    """
    db_path = r'\\ll\D\xtrssvjj\db\dpd.db'    
    print(f"adname: {adname}")    
    audio_file = os.path.join(r'\\ll\D\xtrssvjj', f"{adname}.mp3")
    print(f"音频文件: {audio_file}")
    
    if not os.path.exists(audio_file):
        print(f"错误：音频文件不存在: {audio_file}")
        return False
    
    audio_duration = get_file_duration(audio_file)
    print(f"音频总长度: {audio_duration/1000} 秒")
    
    cn_audio_dir = f"{adname}_cn_audio"
    en_tts_dir = os.path.join(r'\\ll\D\xtrssvjj', 'tts', adname)
    
    if not os.path.exists(en_tts_dir):
        print(f"错误：英文TTS目录不存在: {en_tts_dir}")
        return False
    
    if os.path.exists(cn_audio_dir):
        try:
            shutil.rmtree(cn_audio_dir)
        except Exception as e:
            print(f"警告：删除目录失败: {e}")
    try:
        os.makedirs(cn_audio_dir, exist_ok=True)
    except Exception as e:
        print(f"错误：创建目录失败: {e}")
        return False
    print('从数据库中查询字幕句数...')
    subtitles = get_subtitles(adid, db_path)
    print(f"找到 {len(subtitles)} 句字幕")
    
    if not subtitles:
        print("错误：未找到字幕信息")
        return False
    print('调整字幕句时间...')
    enhanced_subtitles = []
    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 = audio_duration
            endgap = nextstart - end if audio_duration > end else 0
        
        if i == 0:
            startpos = 0
        else:
            startpos = (prevend + start) // 2
        
        if i == len(subtitles)-1:
            endpos = audio_duration - 1
        else:
            endpos = (end + nextstart) // 2
        
        if i == 0:
            addstart = 0
        else:
            addstart = 400 - (start - startpos)
            if addstart <= 0:
                addstart = 0
        
        if i == len(subtitles)-1:
            addend = 0
        else:
            addend = 400 - (endpos - end)
            if addend <= 0:
                addend = 0
        
        enhanced_subtitles.append((idx, start, end, startpos, endpos, addstart, addend, cn, en))
    
    print("\n=== 步骤1: 截取中文音频片段 ===")
    for i, (idx, start, end, startpos, endpos, addstart, addend, cn, en) in enumerate(enhanced_subtitles):
        start_sec = startpos / 1000
        duration_sec = (endpos - startpos) / 1000
        
        output_path = os.path.join(cn_audio_dir, f"seg{idx:03d}.mp3")
        
        cmd = [
            "ffmpeg", "-y",
            "-ss", str(start_sec),
            "-t", str(duration_sec),
            "-i", audio_file,
            "-acodec", "libmp3lame",
            "-ar", "44100",
            "-ac", "2",
            output_path
        ]
        
        subprocess.run(cmd, capture_output=True)
        
        actual_duration = get_file_duration(output_path)
        
        new_filename = f"seg{idx:03d}-{startpos}-{endpos}-{actual_duration}.mp3"
        new_path = os.path.join(cn_audio_dir, new_filename)
        
        if os.path.exists(new_path):
            os.remove(new_path)
        os.rename(output_path, new_path)
        
        if i % 100 == 0:
            print(f"截取音频 {i+1}/{len(enhanced_subtitles)}")
    
    print(f"完成！截取了 {len(enhanced_subtitles)} 个音频片段")
    print(f"输出目录: {cn_audio_dir}")
    
    print("\n=== 步骤2: 拼接双语音频 ===")
    with tempfile.TemporaryDirectory() as temp_dir:
        filelist_path = os.path.join(temp_dir, "filelist.txt")
        
        with open(filelist_path, 'w', encoding='utf-8') as f:
            for i, (idx, start, end, startpos, endpos, addstart, addend, cn, en) in enumerate(enhanced_subtitles):
                cn_audio_file = os.path.join(cn_audio_dir, f"seg{idx:03d}-{startpos}-{endpos}-*.mp3")
                cn_files = glob.glob(cn_audio_file)
                if cn_files:
                    cn_file_abs = os.path.abspath(cn_files[0])
                    f.write(f"file '{cn_file_abs}'\n")
                
                if addend and addend > 0:
                    silence_file = os.path.join(temp_dir, f"silence_end_{idx}.mp3")
                    generate_silence(addend, silence_file)
                    silence_file_abs = os.path.abspath(silence_file)
                    f.write(f"file '{silence_file_abs}'\n")
                
                # 查找 TTS 文件，使用通配符匹配
                en_tts_pattern = os.path.join(en_tts_dir, f"*-{idx:04d}.mp3")
                en_tts_files = glob.glob(en_tts_pattern)
                if en_tts_files:
                    # 调整TTS语速为70%
                    tts_file = en_tts_files[0]
                    slowed_tts_file = os.path.join(temp_dir, f"slowed_tts_{idx:04d}.mp3")
                    # 使用FFmpeg调整语速，保持声调
                    subprocess.run([
                        'ffmpeg', '-y', '-i', tts_file, 
                        '-filter:a', 'atempo=0.7', 
                        '-ac', '2', '-ar', '44100', 
                        slowed_tts_file
                    ], capture_output=True)
                    en_tts_file_abs = os.path.abspath(slowed_tts_file)
                    f.write(f"file '{en_tts_file_abs}'\n")
                    if i%100==0:
                        print(f"添加 TTS 文件 (70%速度): {en_tts_files[0]}")
                
                if i < len(enhanced_subtitles) - 1:
                    next_addstart = enhanced_subtitles[i+1][5]
                    if next_addstart and next_addstart > 0:
                        silence_file = os.path.join(temp_dir, f"silence_start_{i+1}.mp3")
                        generate_silence(next_addstart, silence_file)
                        silence_file_abs = os.path.abspath(silence_file)
                        f.write(f"file '{silence_file_abs}'\n")
        
        output_file = f"{adname}_bilingual.mp3"
        cmd = [
            "ffmpeg", "-y",
            "-f", "concat",
            "-safe", "0",
            "-i", filelist_path,
            "-acodec", "libmp3lame",
            "-ar", "44100",
            "-ac", "2",
            output_file
        ]
        
        print("开始拼接双语音频...")
        result = subprocess.run(cmd, capture_output=True)
        
        if result.returncode == 0:
            print(f"拼接完成！输出文件: {output_file}")
            return True
        else:
            try:
                error_msg = result.stderr.decode('utf-8', errors='replace')
            except:
                try:
                    error_msg = result.stderr.decode('gbk', errors='replace')
                except:
                    error_msg = str(result.stderr)
            print(f"拼接失败！错误信息: {error_msg}")
            return False


def main():
    """
    主函数
    """
    if len(sys.argv) != 2:
        print("用法: python joinbiliad.py <adid>")
        print("示例: python joinbiliad.py 8496")
        sys.exit(1)
    
    try:
        adid = int(sys.argv[1])
    except ValueError:
        print("错误：adid必须是数字")
        sys.exit(1)
    
    print(f"=== 双语音频制作工具 ===")
    print(f"adid: {adid}")
    
    success = extract_and_combine(adid)
    
    if success:
        print("\n制作完成！")
    else:
        print("\n制作失败！")
        sys.exit(1)


if __name__ == "__main__":
    main()
