from ui import Ui_Form
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QPoint
from PyQt5 import QtGui, QtCore
from engine import Player, EventType
import sys, threading, re, os, subprocess, time, configparser



class MainWindow(QWidget, Ui_Form):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.show()
#---------------------------------------------------------------
        #事件关联
        self.btn_set_in.clicked.connect(self.set_in_p)
        self.btn_set_out.clicked.connect(self.set_out_p)
        self.btn_add_item.clicked.connect(self.add_item)
        self.btn_open.clicked.connect(self.open_file)
        self.btn_output.clicked.connect(self.set_save_path)
        self.btn_start_edit.clicked.connect(self.edit_start)
        self.btn_play.clicked.connect(self.play)
        self.comboBox.activated.connect(self.choose_codec)
        self.slider_progress.signal_val_change.connect(self.slider_progress_change)
        self.slider_progress.signal_press.connect(self.slider_progress_change)
        self.slider_trim.signal_val_change.connect(self.slider_trim_change)
        self.slider_trim.signal_press.connect(self.slider_trim_press)
        self.slider_trim.signal_release.connect(self.slider_trim_release)
        self.vlistwidget.itemClicked.connect(self.choose_video)
        self.ilistwidget.itemClicked.connect(self.choose_item)
        self.vlistwidget.currentItemChanged.connect(self.video_change)
        self.ilistwidget.currentItemChanged.connect(self.item_change)
        self.vlistwidget.customContextMenuRequested.connect(self.vlistwidget_requested)
        self.ilistwidget.customContextMenuRequested.connect(self.ilistwidget_requested)
#---------------------------------------------------------------
        #图标设置
        self.setWindowIcon(QtGui.QIcon("icon.ico"))
        #
        self.widget_screen.setEnabled(False)
#---------------------------------------------------------------
        #vlc播放器
        self.mPlayer = Player()
        self.mPlayer.set_window(self.widget_screen.winId())
        #监听事件
        self.mPlayer.add_callback(EventType.MediaPlayerTimeChanged, self.time_changed)
#---------------------------------------------------------------
        #初始化变量
        self.init_var()
#---------------------------------------------------------------
        #初始化函数
    def init_var(self):
        self.in_p = 0
        self.out_p = 0
        self.paly_file = ""
        self.vcodec = "none"
        self.filepath = ""
        self.savepath = ""
        self.videolist = []
        self.itemlist = []
        self.loop = False
        self.getconfig()
#---------------------------------------------------------------
    def setconfig(self):
        config = configparser.ConfigParser()
        config.add_section("Setting")
        config.set("Setting", "filepath", self.filepath)
        config.set("Setting", "savepath", self.savepath)
        with open("config.ini", "w") as f:
            config.write(f)

    def getconfig(self):
        config = configparser.ConfigParser()
        if os.path.exists("config.ini"):
            config.read("config.ini")
            self.filepath = config.get("Setting", "filepath")
            self.savepath = config.get("Setting", "savepath")
            if not os.path.exists(self.savepath):
                self.savepath = ""
        else:
            config.add_section("Setting")
            config.set("Setting", "filepath", "")
            config.set("Setting", "savepath", "")
            with open("config.ini", "w") as f:
                config.write(f)
            self.filepath = ""
            self.filepath = ""
#---------------------------------------------------------------
    def resizeEvent(self, event):
        #QPoint(x, y) for x in range(3, self.width() - 220) for y in range(1, self.height() - 130)
        self._screen_rect = {"ltx":3, "lty":3, "rbx":self.width() - 220, "rby":self.height() - 130}
    #鼠标事件
    def mousePressEvent(self, event):
        pass
    def mouseReleaseEvent(self, event):
        pass
    def mouseMoveEvent(self, event):
        pass
    #键盘事件
    def keyPressEvent(self, event):
        if self.mPlayer.get_state() != -1:
            if event.key() == 32:
                self.play()
            if event.key() == 73:
                self.set_in_p()
            if event.key() == 79:
                self.set_out_p()
                
            if event.key() == 16777234:
                curtime = self.mPlayer.get_time() - 5000
                self.slider_progress_change(curtime / self.length * 100000)
            if event.key() == 16777236:
                curtime = self.mPlayer.get_time() + 5000
                self.slider_progress_change(curtime / self.length * 100000)
            if event.key() == 16777235:
                curtime = self.mPlayer.get_time() + 10000
                self.slider_progress_change(curtime / self.length * 100000)
            if event.key() == 16777237:
                curtime = self.mPlayer.get_time() - 10000
                self.slider_progress_change(curtime / self.length * 100000)
        pass
    def keyReleaseEvent(self, event):
        pass
    #关闭事件
    def closeEvent(self, event):
        self.loop = False
        sys.exit(app.exec_())
#---------------------------------------------------------------
    #窗口响应
    def set_in_p(self, ctime = None):
        if ctime:
            self.in_p = ctime
        else:
            self.in_p = self.mPlayer.get_time()
        self.label_in_p.setText(self.time2hms(self.in_p))

    def set_out_p(self, ctime = None):
        if ctime:
            self.out_p = ctime
        else:
            self.out_p = self.mPlayer.get_time()
        self.label_out_p.setText(self.time2hms(self.out_p))
        
    def add_item(self):
        in_p = self.in_p
        out_p = self.out_p
        if in_p > out_p:
            in_p, out_p = out_p, in_p
        if in_p == out_p:
            return
        item = {"in_p": in_p, "out_p":out_p, "file":self.play_file}
        self.itemlist.append(item)
        path, name = os.path.split(self.play_file)
        name, ext = os.path.splitext(name)
        file = name + "-" + str(self.in_p) + "-" + str(self.out_p) + ext
        self.ilistwidget.addItem(file)


    def edit_start(self):
        edit_thread = threading.Thread(target = self.start_edit, args = ())
        edit_thread.start()
        
    def open_file(self):
        files = QFileDialog.getOpenFileNames(self, "打开文件", self.filepath, "*.3g2 *.3gp *.3gp2 *.3gpp *.amv *.asf *.avi *.bik *.bin*.divx *.drc\
                                           *.dv *.f4v *.flv *.gvi *.gxf *.iso *.m1v *.m2v *.m2t *.m2ts *.m4v *.mkv *.mov *.mp2 *.mp4\
                                           *.mp4v *.mpe *.mpeg *.mpeg1 *.mpeg2 *.mpeg4 *.mpg *.mpv2 *.mts *.mxf *.mxg *.nsv *.nuv *.ogg\
                                           *.ogm *.ogv *.ps *.rec *.rm *.rmvb *.rpl *.thp *.tod *.ts *.tts *.txd *.vob *.vro *.webm\
                                           *.wm *.wmv *.wtv *.xesc", None, QFileDialog.ShowDirsOnly)
        for file in files[0]:
            self.videolist.append(file)
            path, name = os.path.split(file)
            self.vlistwidget.addItem(name)
        if files[0]:
            self.filepath = path
            self.setconfig()
            self.play_file = files[0][0]
            self.loop = False
            self.mPlayer.play(self.play_file)
            self.btn_play.setText("暂停")

    def set_save_path(self):
        path = QFileDialog.getExistingDirectory(self, "打开文件夹", self.savepath)
        if path != "":
            self.savepath = path
            self.setconfig()

    def choose_codec(self):
        if self.comboBox.currentText() != "选择编码":
            self.vcodec = self.comboBox.currentText()
        else:
            self.vcodec = "none"
    def slider_trim_change(self, val = None):
        state = self.mPlayer.get_state()
        if state != -1:
            if state == 1:
                #self.mPlayer.pause()
                pass
            if abs(val) == 1500:
                return
            self.slider_trim.setValue(val)
            ntime = self.curtime + val
            if ntime < 100:
                ntime = 100
            if ntime > self.length:
                ntime = self.length
            self.mPlayer.set_time(ntime)
            self.slider_progress_change()
            
    def slider_trim_press(self, val = None):
        if self.mPlayer.get_state() != -1:
            self.slider_trim.setValue(val)
            self.curtime = self.mPlayer.get_time()

    def slider_trim_release(self):
        self.slider_trim.setValue(0)
        
    def slider_progress_change(self, val = None):
        if self.mPlayer.get_state() != -1:
            self.length = self.mPlayer.get_length()
            if not val:
                ctime = self.mPlayer.get_time()
                val = int(ctime / self.length * 100000)
            else:
                ctime = int(self.length * val / 100000)
                self.mPlayer.set_time(ctime)

            if val < 0:
                val = 0
            elif val > 99999:
                val = 99999
            self.label_current.setText(self.time2hms(ctime))
            self.label_length.setText(self.time2hms(self.length))
            self.slider_progress.setValue(int(val))

    def choose_video(self):
        self.loop = False
        idx = self.vlistwidget.currentRow()
        self.play_file = self.videolist[idx]
        self.mPlayer.play(self.play_file)
        self.btn_play.setText("暂停")

    def video_change(self):
        idx = self.vlistwidget.currentRow()
        pass
    def vlistwidget_requested(self, pos):
        item = self.vlistwidget.itemAt(pos)
        if item:
            menu = QMenu()
            action_v_deleate = menu.addAction("删除当前文件")
            action_v_deleate.triggered.connect(self.vlist_deleate_item)
        else:
            menu = QMenu()
            action_openfile = menu.addAction("打开文件")
            action_openfile.triggered.connect(self.open_file)
            action_v_clear = menu.addAction("清空")
            action_v_clear.triggered.connect(self.vlist_clear)
        menu.exec(QtGui.QCursor.pos())

    def choose_item(self):
        self.loop = True
        idx = self.ilistwidget.currentRow()
        item = self.itemlist[idx]
        self.set_in_p(item["in_p"])
        self.set_out_p(item["out_p"])
        if self.play_file != item["file"]:
            self.play_file = item["file"]
            self.mPlayer.play(self.play_file)
        else:
            if self.mPlayer.get_state() == 0:
                self.play()
        self.mPlayer.set_time(item["in_p"])
        loop_thread = threading.Thread(target = self.video_loop, args = ())
        loop_thread.start()
    
    def item_change(self):
        idx = self.ilistwidget.currentRow()

    def ilistwidget_requested(self, pos):
        item = self.ilistwidget.itemAt(pos)
        if item:
            menu = QMenu()
            action_i_deleate = menu.addAction("删除当前文件")
            action_i_deleate.triggered.connect(self.ilist_deleate_item)
        else:
            menu = QMenu()
            action_set_savepath = menu.addAction("输出目录")
            action_set_savepath.triggered.connect(self.set_save_path)
            action_i_clear = menu.addAction("清空")
            action_i_clear.triggered.connect(self.ilist_clear)
        menu.exec(QtGui.QCursor.pos())
#---------------------------------------------------------------
    #loop
    def video_loop(self):
        while self.loop and self.mPlayer.get_state() == 1:
            curtime = self.mPlayer.get_time()
            if curtime < self.in_p - 100:
                self.mPlayer.set_time(self.in_p)
            if curtime > self.out_p + 100:
                self.mPlayer.set_time(self.in_p)
            time.sleep(0.1)

#---------------------------------------------------------------
    #vlc相关
    def play(self):
        state = self.mPlayer.get_state()
        if state == 1:
            self.mPlayer.pause()
            self.btn_play.setText("播放")
        elif state == 0:
            self.mPlayer.play()
            self.btn_play.setText("暂停")
        else:
            pass
    def set_play_file(self):
        self.mPlayer.set_file(self.play_file)
    def time_changed(self, event):
        self.slider_progress_change()
 

#---------------------------------------------------------------
    #ffmpeg相关 调用ffmpeg裁剪编码
    def start_edit(self):
        self.label_state.setText("开始")
        self.btn_start_edit.setEnabled(False)
        length = len(self.itemlist)

        if length != 0:
            for i in range(length):
                item = self.itemlist[i]
                item["item_id"] = i + 1
                self.run_ffmpeg(item)
        else:
            in_p = self.in_p
            out_p = self.out_p
            if in_p != out_p:
                if in_p > out_p:
                    in_p, out_p = out_p, in_p
                item = {"in_p": in_p, "out_p":out_p, "file":self.play_file, "item_id":1}
                self.run_ffmpeg(item)
                
        self.label_state.setText("完成")
        self.btn_start_edit.setEnabled(True)
        
    def run_ffmpeg(self, item):
        in_p = item["in_p"]
        out_p = item["out_p"]
        file = item["file"]
        item_id = item["item_id"]
        path, file = os.path.split(file)
        name, ext = os.path.splitext(file)
        in_file = "\"" + path + "/" + name + ext + "\""
        if self.savepath == "":
            path = path + "/temp/"
            if not os.path.exists(path):
                os.mkdir(path)
        else:
            path = self.savepath + "/"
        if self.vcodec == "none":
            out_file = "\"" + path + name + "-s" + str(in_p//1000) + "-e" + str(out_p//1000) + ext + "\""
            cmd = "ffmpeg" + " -ss "  + self.time2hms(in_p) + " -accurate_seek" + " -i " + in_file + " -t " + self.time2hms(out_p - in_p) + " -vcodec copy -acodec aac" + " -avoid_negative_ts 1" + " -y " + out_file
        else:
            out_file = "\"" + path + name + "-s" + str(in_p//1000) + "-e" + str(out_p//1000) + ".mp4" + "\""
            cmd = "ffmpeg" + " -i " + in_file + " -ss " + self.time2hms(in_p) + " -t " + self.time2hms(out_p - in_p) + " -vcodec " + self.vcodec + " -acodec aac" + " -y " + out_file
        #调用控制台 运行ffmpeg命令
        info = subprocess.STARTUPINFO()
        info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
        mProcess = subprocess.Popen(cmd,stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, startupinfo=info)
        length = abs(out_p - in_p)
        self.get_stdout(mProcess, length, item_id)

    def get_stdout(self, mProcess, length, idx):
        while mProcess.poll() is None:
            try:
                line = mProcess.stdout.readline()
            except:
                continue
            line = re.search("time=(.+?) bitrate=", line)
            if line:
                c = line[1]
                c = c.split(":")
                c = float(c[0]) * 3600 + float(c[1]) * 60 + float(c[2])
                per = str(int(c * 1000 / length * 100)) + "%"
                self.label_state.setText("第" + str(idx) + "段"+ ":" + per)

        if mProcess.poll() != 0:
            self.label_state.setText("ffmpeg 出错啦！")
#---------------------------------------------------------------
    #其他基础函数
    def time2hms(self, timenum):
        ms = str(timenum % 1000).zfill(3)
        s = str(timenum // 1000 % 60).zfill(2)
        m = str(timenum // 60000 % 60).zfill(2)
        h = str(timenum // 3600000).zfill(2)
        return h + ":" + m + ":" + s + "." + ms
    #列表映射
    def vlist_update(self):
        pass
    def ilist_update(self):
        pass
    def vlist_deleate_item(self):
        idx = self.vlistwidget.currentRow()
        self.vlistwidget.takeItem(idx)
        del self.videolist[idx]
        
    def vlist_clear(self):
        self.vlistwidget.clear()
        self.videolist = []
        
    def ilist_deleate_item(self):
        idx = self.ilistwidget.currentRow()
        self.ilistwidget.takeItem(idx)
        del self.itemlist[idx]
        
    def ilist_clear(self):
        self.ilistwidget.clear()
        self.itemlist = []
    

#---------------------------------------------------------------

if "__main__" == __name__:
    app = QApplication(sys.argv)
    win = MainWindow()
    sys.exit(app.exec_())
