import sys
import os
import subprocess
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel
from PyQt5.QtCore import Qt, QThread, pyqtSignal

class VideoProcessor(QThread):
    update_status = pyqtSignal(str)

    def __init__(self, file_path):
        super().__init__()
        self.file_path = file_path

    def run(self):
        self.update_status.emit(f"正在扫描文件: {os.path.basename(self.file_path)}...")
        
        # 使用 ffprobe 获取所有视频帧的 pts_time 物理顺序
        cmd_probe = [
            'ffprobe', '-loglevel', 'error', 
            '-select_streams', 'v:0',
            '-show_entries', 'frame=pts_time', 
            '-of', 'csv=p=0', self.file_path
        ]
        
        try:
            result = subprocess.run(cmd_probe, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, creationflags=subprocess.CREATE_NO_WINDOW)
            lines = [line.strip() for line in result.stdout.split('\n') if line.strip()]
        except Exception as e:
            self.update_status.emit("ffprobe 运行失败，请检查是否安装了 FFmpeg。")
            return

        if not lines:
            self.update_status.emit("未提取到有效时间戳，可能文件损坏。")
            return

        self.update_status.emit("时间轴扫描完成，正在分析断点...")
        
        split_frames = []
        segment_infos = []
        current_segment = {'start_idx': 0, 'start_pts': None, 'last_pts': None}

        for idx, line in enumerate(lines):
            try:
                pts = float(line)
            except ValueError:
                continue
            
            if current_segment['start_pts'] is None:
                current_segment['start_pts'] = pts
                current_segment['last_pts'] = pts
                continue
            
            # 核心修正：无论是倒流还是暴涨，只要绝对值跳跃大于 2 秒，就判定为拼接断层
            if abs(pts - current_segment['last_pts']) > 2.0:
                duration = abs(current_segment['last_pts'] - current_segment['start_pts'])
                segment_infos.append({
                    'start_idx': current_segment['start_idx'],
                    'end_idx': idx - 1,
                    'keep': duration > 180.0  # 持续时间大于3分钟的认为是正片
                })
                split_frames.append(str(idx))  # 记录断层的物理帧行号
                current_segment = {'start_idx': idx, 'start_pts': pts, 'last_pts': pts}
            else:
                current_segment['last_pts'] = pts

        # 闭合最后一段
        if current_segment['start_pts'] is not None:
            duration = abs(current_segment['last_pts'] - current_segment['start_pts'])
            segment_infos.append({
                'start_idx': current_segment['start_idx'],
                'end_idx': len(lines) - 1,
                'keep': duration > 180.0
            })

        if not split_frames:
            if segment_infos and segment_infos[0]['keep']:
                self.update_status.emit("未检测到时间轴断层，视频可能本来就没有广告。")
            else:
                self.update_status.emit("未检测到有效长度的正片。")
            return

        self.update_status.emit(f"检测到 {len(split_frames)} 个断层，正在利用物理帧强行切片...")

        # 利用 segment_frames 按照物理帧无损切片，完美避开时间戳重叠导致的鬼打墙
        split_frames_str = ",".join(split_frames)
        cmd_segment = [
            'ffmpeg', '-y', '-i', self.file_path,
            '-c', 'copy', '-f', 'segment',
            '-segment_frames', split_frames_str,
            'seg_%03d.ts'
        ]
        subprocess.run(cmd_segment, creationflags=subprocess.CREATE_NO_WINDOW)

        self.update_status.emit("切片完成，正在无损合并正片片段...")

        # 生成合并清单
        concat_list = "concat_list.txt"
        has_valid_content = False
        with open(concat_list, "w", encoding="utf-8") as f:
            for i, info in enumerate(segment_infos):
                seg_name = f"seg_{i:03d}.ts"
                if info['keep'] and os.path.exists(seg_name):
                    f.write(f"file '{seg_name}'\n")
                    has_valid_content = True

        out_file = self.file_path.replace(".ts", "_no_ads.ts")
        
        if has_valid_content:
            cmd_concat = [
                'ffmpeg', '-y', '-f', 'concat', '-safe', '0',
                '-i', concat_list, '-c', 'copy', out_file
            ]
            subprocess.run(cmd_concat, creationflags=subprocess.CREATE_NO_WINDOW)
            status_msg = f"处理完成！无广告版本已保存为: {os.path.basename(out_file)}"
        else:
            status_msg = "未找到符合长度的正片片段，合并取消。"

        # 清理所有生成的临时切片文件
        if os.path.exists(concat_list):
            os.remove(concat_list)
        for i in range(len(segment_infos)):
            seg_name = f"seg_{i:03d}.ts"
            if os.path.exists(seg_name):
                os.remove(seg_name)

        self.update_status.emit(status_msg)


class DropWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("TS 去广告神器 升级版")
        self.resize(400, 200)
        self.setAcceptDrops(True)
        
        layout = QVBoxLayout()
        self.label = QLabel("请将带有广告的 TS 电影拖入此窗口\n(采用物理帧精准剥离技术)", self)
        self.label.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.label)
        self.setLayout(layout)
        self.processor = None
        
    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            event.ignore()
            
    def dropEvent(self, event):
        urls = event.mimeData().urls()
        if urls:
            file_path = urls[0].toLocalFile()
            if file_path.lower().endswith('.ts'):
                self.processor = VideoProcessor(file_path)
                self.processor.update_status.connect(self.update_label)
                self.processor.start()
            else:
                self.label.setText("请拖入 .ts 格式的视频文件！")

    def update_label(self, text):
        self.label.setText(text)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = DropWindow()
    window.show()
    sys.exit(app.exec_())