Ejemplo n.º 1
0
 def __createTextWidgetForAxis__(self, axis):
     textWidget = AxisTextWidget(axis, self)
     self.axisModel.addAxisObserver(textWidget, axis)
     showInX = QRadioButton()
     showInY = QRadioButton()
     showInX.setObjectName(str(axis))
     showInY.setObjectName(str(axis))
     showInX.setLayoutDirection(Qt.RightToLeft)
     showInY.setLayoutDirection(Qt.RightToLeft)
     showInX.setMaximumSize(24, 24)
     showInY.setMaximumSize(24, 24)
     self.xGroup.addButton(showInX)
     self.yGroup.addButton(showInY)
     gridLayout = QGridLayout()
     gridLayout.addWidget(textWidget, 0, 0, 1, 2)
     gridLayout.addWidget(showInX, 0, 2, 1, 1)
     gridLayout.addWidget(showInY, 0, 3, 1, 1)
     self.addLayoutToScrollArea(gridLayout)
Ejemplo n.º 2
0
class AudioVideoTab(QWidget):
    def __init__(self, parent):
        super(AudioVideoTab, self).__init__(parent)
        self.parent = parent
        self.name = 'AudioVideo'
        self.formats = [
            '3gp', 'aac', 'ac3', 'afc', 'aiff', 'amr', 'asf', 'au', 'avi',
            'dvd', 'flac', 'flv', 'mka', 'mkv', 'mmf', 'mov', 'mp3', 'mp4',
            'mpg', 'ogg', 'ogv', 'psp', 'rm', 'spx', 'vob', 'wav', 'webm',
            'wma', 'wmv'
        ]
        self.extra_formats = [
            'aifc', 'm2t', 'm4a', 'm4v', 'mp2', 'mpeg', 'ra', 'ts'
        ]

        nochange = self.tr('No Change')
        frequency_values = [nochange, '22050', '44100', '48000']
        bitrate_values = [
            nochange, '32', '96', '112', '128', '160', '192', '256', '320'
        ]
        pattern = QRegExp(r'^[1-9]\d*')
        validator = QRegExpValidator(pattern, self)

        converttoLabel = QLabel(self.tr('Convert to:'))
        self.extComboBox = QComboBox()
        self.extComboBox.addItems(self.formats + [self.tr('Other')])
        self.extComboBox.setMinimumWidth(130)
        self.extLineEdit = QLineEdit()
        self.extLineEdit.setMaximumWidth(85)
        self.extLineEdit.setEnabled(False)
        hlayout1 = pyqttools.add_to_layout(QHBoxLayout(), converttoLabel, None,
                                           self.extComboBox, self.extLineEdit)
        commandLabel = QLabel(self.tr('Command:'))
        self.commandLineEdit = QLineEdit()
        self.presetButton = QPushButton(self.tr('Preset'))
        self.defaultButton = QPushButton(self.tr('Default'))
        hlayout2 = pyqttools.add_to_layout(QHBoxLayout(), commandLabel,
                                           self.commandLineEdit,
                                           self.presetButton,
                                           self.defaultButton)

        sizeLabel = QLabel(self.tr('Video Size:'))
        aspectLabel = QLabel(self.tr('Aspect:'))
        frameLabel = QLabel(self.tr('Frame Rate (fps):'))
        bitrateLabel = QLabel(self.tr('Video Bitrate (kbps):'))

        self.widthLineEdit = pyqttools.create_LineEdit((50, 16777215),
                                                       validator, 4)
        self.heightLineEdit = pyqttools.create_LineEdit((50, 16777215),
                                                        validator, 4)
        label = QLabel('x')
        layout1 = pyqttools.add_to_layout(QHBoxLayout(), self.widthLineEdit,
                                          label, self.heightLineEdit)
        self.aspect1LineEdit = pyqttools.create_LineEdit((35, 16777215),
                                                         validator, 2)
        self.aspect2LineEdit = pyqttools.create_LineEdit((35, 16777215),
                                                         validator, 2)
        label = QLabel(':')
        layout2 = pyqttools.add_to_layout(QHBoxLayout(), self.aspect1LineEdit,
                                          label, self.aspect2LineEdit)
        self.frameLineEdit = pyqttools.create_LineEdit(None, validator, 4)
        self.bitrateLineEdit = pyqttools.create_LineEdit(None, validator, 6)

        labels = [sizeLabel, aspectLabel, frameLabel, bitrateLabel]
        widgets = [layout1, layout2, self.frameLineEdit, self.bitrateLineEdit]

        videosettings_layout = QHBoxLayout()
        for a, b in zip(labels, widgets):
            text = a.text()
            a.setText('<html><p align="center">{0}</p></html>'.format(text))
            layout = pyqttools.add_to_layout(QVBoxLayout(), a, b)
            videosettings_layout.addLayout(layout)

        freqLabel = QLabel(self.tr('Frequency (Hz):'))
        chanLabel = QLabel(self.tr('Channels:'))
        bitrateLabel = QLabel(self.tr('Audio Bitrate (kbps):'))

        self.freqComboBox = QComboBox()
        self.freqComboBox.addItems(frequency_values)
        self.chan1RadioButton = QRadioButton('1')
        self.chan1RadioButton.setMaximumSize(QSize(51, 16777215))
        self.chan2RadioButton = QRadioButton('2')
        self.chan2RadioButton.setMaximumSize(QSize(51, 16777215))
        self.group = QButtonGroup()
        self.group.addButton(self.chan1RadioButton)
        self.group.addButton(self.chan2RadioButton)
        spcr1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)
        spcr2 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)
        chanlayout = pyqttools.add_to_layout(QHBoxLayout(), spcr1,
                                             self.chan1RadioButton,
                                             self.chan2RadioButton, spcr2)
        self.audio_bitrateComboBox = QComboBox()
        self.audio_bitrateComboBox.addItems(bitrate_values)

        labels = [freqLabel, chanLabel, bitrateLabel]
        widgets = [self.freqComboBox, chanlayout, self.audio_bitrateComboBox]

        audiosettings_layout = QHBoxLayout()
        for a, b in zip(labels, widgets):
            text = a.text()
            a.setText('<html><p align="center">{0}</p></html>'.format(text))
            layout = pyqttools.add_to_layout(QVBoxLayout(), a, b)
            audiosettings_layout.addLayout(layout)

        hidden_layout = pyqttools.add_to_layout(QVBoxLayout(),
                                                videosettings_layout,
                                                audiosettings_layout)

        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.moreButton = QPushButton(QApplication.translate('Tab', 'More'))
        self.moreButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed))
        self.moreButton.setCheckable(True)
        hlayout3 = pyqttools.add_to_layout(QHBoxLayout(), line,
                                           self.moreButton)

        self.frame = QFrame()
        self.frame.setLayout(hidden_layout)
        self.frame.hide()

        final_layout = pyqttools.add_to_layout(QVBoxLayout(), hlayout1,
                                               hlayout2, hlayout3, self.frame)
        self.setLayout(final_layout)

        self.presetButton.clicked.connect(self.choose_preset)
        self.defaultButton.clicked.connect(self.set_default_command)
        self.moreButton.toggled.connect(self.frame.setVisible)
        self.moreButton.toggled.connect(self.resize_parent)
        self.extComboBox.currentIndexChanged.connect(
            lambda: self.extLineEdit.setEnabled(self.extComboBox.currentIndex(
            ) == len(self.formats)))
        self.widthLineEdit.textChanged.connect(
            lambda: self.command_elements_change('size'))
        self.heightLineEdit.textChanged.connect(
            lambda: self.command_elements_change('size'))
        self.aspect1LineEdit.textChanged.connect(
            lambda: self.command_elements_change('aspect'))
        self.aspect2LineEdit.textChanged.connect(
            lambda: self.command_elements_change('aspect'))
        self.frameLineEdit.textChanged.connect(
            lambda: self.command_elements_change('frames'))
        self.bitrateLineEdit.textChanged.connect(
            lambda: self.command_elements_change('video_bitrate'))
        self.freqComboBox.currentIndexChanged.connect(
            lambda: self.command_elements_change('frequency'))
        self.audio_bitrateComboBox.currentIndexChanged.connect(
            lambda: self.command_elements_change('audio_bitrate'))
        self.chan1RadioButton.clicked.connect(
            lambda: self.command_elements_change('channels1'))
        self.chan2RadioButton.clicked.connect(
            lambda: self.command_elements_change('channels2'))

    def resize_parent(self):
        """Resize MainWindow."""
        height = MAIN_FIXED_HEIGHT if self.frame.isVisible() else MAIN_HEIGHT
        self.parent.setMinimumSize(MAIN_WIDTH, height)
        self.parent.resize(MAIN_WIDTH, height)

    def clear(self):
        """Clear all values of graphical widgets."""
        lines = [
            self.commandLineEdit, self.widthLineEdit, self.heightLineEdit,
            self.aspect1LineEdit, self.aspect2LineEdit, self.frameLineEdit,
            self.bitrateLineEdit, self.extLineEdit
        ]
        for i in lines:
            i.clear()

        self.freqComboBox.setCurrentIndex(0)
        self.audio_bitrateComboBox.setCurrentIndex(0)
        self.group.setExclusive(False)
        self.chan1RadioButton.setChecked(False)
        self.chan2RadioButton.setChecked(False)
        self.group.setExclusive(True)
        # setExclusive(False) in order to be able to uncheck checkboxes and
        # then setExclusive(True) so only one radio button can be set

    def ok_to_continue(self):
        """
        Check if everything is ok with audiovideotab to continue conversion.

        Check if:
        - Either ffmpeg or avconv are installed.
        - Desired extension is valid.
        - self.commandLineEdit is empty.

        Return True if all tests pass, else False.
        """
        if not self.parent.ffmpeg and not self.parent.avconv:
            QMessageBox.warning(
                self, 'FF Multi Converter - ' + self.tr('Error!'),
                self.
                tr('Neither ffmpeg nor avconv are installed.'
                   '\nYou will not be able to convert audio/video files until you'
                   ' install one of them.'))
            return False
        if self.extLineEdit.isEnabled():
            text = str(self.extLineEdit.text()).strip()
            if len(text.split()) != 1 or text[0] == '.':
                QMessageBox.warning(
                    self, 'FF Multi Converter - ' + self.tr('Error!'),
                    self.tr('Extension must be one word and must '
                            'not start with a dot.'))
                self.extLineEdit.selectAll()
                self.extLineEdit.setFocus()
                return False
        if not self.commandLineEdit.text():
            QMessageBox.warning(
                self, 'FF Multi Converter - ' + self.tr('Error!'),
                self.tr('The command LineEdit may not be empty.'))
            self.commandLineEdit.setFocus()
            return False
        return True

    def set_default_command(self):
        """Set the default value to self.commandLineEdit."""
        self.clear()
        self.commandLineEdit.setText(self.parent.default_command)

    def choose_preset(self):
        """
        Open the presets dialog and update self.commandLineEdit,
        self.extComboBox and self.extLineEdit with the appropriate values.
        """
        dialog = presets_dlgs.ShowPresets()
        if dialog.exec_() and dialog.the_command is not None:
            self.commandLineEdit.setText(dialog.the_command)
            self.commandLineEdit.home(False)
            find = self.extComboBox.findText(dialog.the_extension)
            if find >= 0:
                self.extComboBox.setCurrentIndex(find)
            else:
                self.extComboBox.setCurrentIndex(len(self.formats))
                self.extLineEdit.setText(dialog.the_extension)

    def remove_consecutive_spaces(self, string):
        """Remove any consecutive spaces from a string and return it."""
        temp = string
        string = ''
        for i in temp.split():
            if i:
                string += i + ' '
        return string[:-1]

    def command_elements_change(self, widget):
        """Fill self.commandLineEdit with the appropriate command parameters."""
        command = str(self.commandLineEdit.text())

        if widget == 'size':
            text1 = self.widthLineEdit.text()
            text2 = self.heightLineEdit.text()

            if (text1 or text2) and not (text1 and text2):
                return
            f = re.sub(r'^.*(-s\s+\d+x\d+).*$', r'\1', command)
            if re.match(r'^.*(-s\s+\d+x\d+).*$', f):
                command = command.replace(f, '').strip()
            if text1 and text2:
                command += ' -s {0}x{1}'.format(text1, text2)

        elif widget == 'aspect':
            text1 = self.aspect1LineEdit.text()
            text2 = self.aspect2LineEdit.text()

            if (text1 or text2) and not (text1 and text2):
                return
            f = re.sub(r'^.*(-aspect\s+\d+:\d+).*$', r'\1', command)
            if re.match(r'^.*(-aspect\s+\d+:\d+).*$', f):
                command = command.replace(f, '').strip()
            if text1 and text2:
                command += ' -aspect {0}:{1}'.format(text1, text2)

        elif widget == 'frames':
            text = self.frameLineEdit.text()
            f = re.sub(r'^.*(-r\s+\d+).*$', r'\1', command)
            if re.match(r'^.*(-r\s+\d+).*$', f):
                command = command.replace(f, '').strip()
            if text:
                command += ' -r {0}'.format(text)

        elif widget == 'video_bitrate':
            text = self.bitrateLineEdit.text()
            f = re.sub(r'^.*(-b\s+\d+k).*$', r'\1', command)
            if re.match(r'^.*(-b\s+\d+k).*$', f):
                command = command.replace(f, '')
            if text:
                command += ' -b {0}k'.format(text)
            command = command.replace('-sameq', '').strip()

        elif widget == 'frequency':
            text = self.freqComboBox.currentText()
            f = re.sub(r'^.*(-ar\s+\d+).*$', r'\1', command)
            if re.match(r'^.*(-ar\s+\d+).*$', f):
                command = command.replace(f, '').strip()
            if text != 'No Change':
                command += ' -ar {0}'.format(text)

        elif widget == 'audio_bitrate':
            text = self.audio_bitrateComboBox.currentText()
            f = re.sub(r'^.*(-ab\s+\d+k).*$', r'\1', command)
            if re.match(r'^.*(-ab\s+\d+k).*$', f):
                command = command.replace(f, '').strip()
            if text != 'No Change':
                command += ' -ab {0}k'.format(text)

        elif widget in ('channels1', 'channels2'):
            text = self.chan1RadioButton.text() if widget == 'channels1' \
                                            else self.chan2RadioButton.text()
            f = re.sub(r'^.*(-ac\s+\d+).*$', r'\1', command)
            if re.match(r'^.*(-ac\s+\d+).*$', f):
                command = command.replace(f, '').strip()
            command += ' -ac {0}'.format(text)

        self.commandLineEdit.clear()
        self.commandLineEdit.setText(self.remove_consecutive_spaces(command))
class AudioVideoTab(QWidget):
    def __init__(self, parent):
        super(AudioVideoTab, self).__init__(parent)
        self.parent = parent
        self.name = "AudioVideo"

        self.defaultStr = self.tr("Default")
        self.DisableStream = self.tr("Disable")

        self.formats = config.video_formats
        frequency_values = [self.defaultStr] + config.video_frequency_values
        bitrate_values = [self.defaultStr] + config.video_bitrate_values

        rotation_options = [
            self.tr("None"),
            "90 " + self.tr("clockwise"),
            "90 " + self.tr("clockwise") + " + " + self.tr("vertical flip"),
            "90 " + self.tr("counter clockwise"),
            "90 " + self.tr("counter clockwise") + " + " + self.tr("vertical flip"),
            "180",
            self.tr("horizontal flip"),
            self.tr("vertical flip"),
        ]

        digits_validator = QRegExpValidator(QRegExp(r"[1-9]\d*"), self)
        digits_validator_wzero = QRegExpValidator(QRegExp(r"\d*"), self)
        digits_validator_minus = QRegExpValidator(QRegExp(r"(-1|[1-9]\d*)"), self)
        time_validator = QRegExpValidator(QRegExp(r"\d{1,2}:\d{1,2}:\d{1,2}\.\d+"), self)

        converttoQL = QLabel(self.tr("Convert to:"))
        self.extQCB = QComboBox()
        self.extQCB.setMinimumWidth(100)
        vidcodecQL = QLabel("Video codec:")
        self.vidcodecQCB = QComboBox()
        self.vidcodecQCB.setMinimumWidth(110)
        audcodecQL = QLabel("Audio codec:")
        self.audcodecQCB = QComboBox()
        self.audcodecQCB.setMinimumWidth(110)

        hlayout1 = utils.add_to_layout(
            "h",
            converttoQL,
            self.extQCB,
            QSpacerItem(180, 20),
            vidcodecQL,
            self.vidcodecQCB,
            audcodecQL,
            self.audcodecQCB,
        )

        commandQL = QLabel(self.tr("Command:"))
        self.commandQLE = QLineEdit()
        self.presetQPB = QPushButton(self.tr("Preset"))
        self.defaultQPB = QPushButton(self.defaultStr)
        hlayout2 = utils.add_to_layout("h", commandQL, self.commandQLE, self.presetQPB, self.defaultQPB)

        sizeQL = QLabel(self.tr("Video Size:"))
        aspectQL = QLabel(self.tr("Aspect:"))
        frameQL = QLabel(self.tr("Frame Rate (fps):"))
        bitrateQL = QLabel(self.tr("Video Bitrate (kbps):"))

        self.widthQLE = utils.create_LineEdit((70, 16777215), digits_validator_minus, 4)
        self.heightQLE = utils.create_LineEdit((70, 16777215), digits_validator_minus, 4)
        label = QLabel('<html><p align="center">x</p></html>')
        layout1 = utils.add_to_layout("h", self.widthQLE, label, self.heightQLE)
        self.aspect1QLE = utils.create_LineEdit((50, 16777215), digits_validator, 2)
        self.aspect2QLE = utils.create_LineEdit((50, 16777215), digits_validator, 2)
        label = QLabel('<html><p align="center">:</p></html>')
        layout2 = utils.add_to_layout("h", self.aspect1QLE, label, self.aspect2QLE)
        self.frameQLE = utils.create_LineEdit((120, 16777215), digits_validator, 4)
        self.bitrateQLE = utils.create_LineEdit((130, 16777215), digits_validator, 6)

        labels = [sizeQL, aspectQL, frameQL, bitrateQL]
        widgets = [layout1, layout2, self.frameQLE, self.bitrateQLE]

        self.preserveaspectQChB = QCheckBox(self.tr("Preserve aspect ratio"))
        self.preservesizeQChB = QCheckBox(self.tr("Preserve video size"))

        preserve_layout = utils.add_to_layout("v", self.preserveaspectQChB, self.preservesizeQChB)

        videosettings_layout = QHBoxLayout()
        for a, b in zip(labels, widgets):
            a.setText('<html><p align="center">{0}</p></html>'.format(a.text()))
            layout = utils.add_to_layout("v", a, b)
            videosettings_layout.addLayout(layout)
            if a == aspectQL:
                # add vidaspectCB in layout after aspectQL
                videosettings_layout.addLayout(preserve_layout)

        freqQL = QLabel(self.tr("Frequency (Hz):"))
        chanQL = QLabel(self.tr("Audio Channels:"))
        bitrateQL = QLabel(self.tr("Audio Bitrate (kbps):"))
        threadsQL = QLabel(self.tr("Threads:"))

        self.freqQCB = QComboBox()
        self.freqQCB.addItems(frequency_values)
        self.chan1QRB = QRadioButton("1")
        self.chan1QRB.setMaximumSize(QSize(51, 16777215))
        self.chan2QRB = QRadioButton("2")
        self.chan2QRB.setMaximumSize(QSize(51, 16777215))
        self.group = QButtonGroup()
        self.group.addButton(self.chan1QRB)
        self.group.addButton(self.chan2QRB)
        spcr1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)
        spcr2 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)
        chanlayout = utils.add_to_layout("h", spcr1, self.chan1QRB, self.chan2QRB, spcr2)
        self.audbitrateQCB = QComboBox()
        self.audbitrateQCB.addItems(bitrate_values)
        self.threadsQLE = utils.create_LineEdit((50, 16777215), digits_validator_wzero, 1)

        labels = [freqQL, bitrateQL, chanQL, threadsQL]
        widgets = [self.freqQCB, self.audbitrateQCB, chanlayout, self.threadsQLE]

        audiosettings_layout = QHBoxLayout()
        for a, b in zip(labels, widgets):
            a.setText('<html><p align="center">{0}</p></html>'.format(a.text()))
            layout = utils.add_to_layout("v", a, b)
            audiosettings_layout.addLayout(layout)

        time_format = " (hh:mm:ss):"
        beginQL = QLabel(self.tr("Split file. Begin time") + time_format)
        self.beginQLE = utils.create_LineEdit(None, time_validator, None)
        durationQL = QLabel(self.tr("Duration") + time_format)
        self.durationQLE = utils.create_LineEdit(None, time_validator, None)

        hlayout4 = utils.add_to_layout("h", beginQL, self.beginQLE, durationQL, self.durationQLE)

        embedQL = QLabel(self.tr("Embed subtitle:"))
        self.embedQLE = QLineEdit()
        self.embedQTB = QToolButton()
        self.embedQTB.setText("...")

        rotateQL = QLabel(self.tr("Rotate:"))
        self.rotateQCB = QComboBox()
        self.rotateQCB.addItems(rotation_options)

        hlayout5 = utils.add_to_layout("h", rotateQL, self.rotateQCB, embedQL, self.embedQLE, self.embedQTB)

        hidden_layout = utils.add_to_layout("v", videosettings_layout, audiosettings_layout, hlayout4, hlayout5)

        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.moreQPB = QPushButton(QApplication.translate("Tab", "More"))
        self.moreQPB.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.moreQPB.setCheckable(True)
        hlayout3 = utils.add_to_layout("h", line, self.moreQPB)

        self.frame = QFrame()
        self.frame.setLayout(hidden_layout)
        self.frame.hide()

        final_layout = utils.add_to_layout("v", hlayout1, hlayout2, hlayout3, self.frame)
        self.setLayout(final_layout)

        self.presetQPB.clicked.connect(self.choose_preset)
        self.defaultQPB.clicked.connect(self.set_default_command)
        self.embedQTB.clicked.connect(self.open_subtitle_file)
        self.moreQPB.toggled.connect(self.frame.setVisible)
        self.moreQPB.toggled.connect(lambda: QTimer.singleShot(100, self.resize_parent))
        self.widthQLE.textChanged.connect(self.command_update_size)
        self.heightQLE.textChanged.connect(self.command_update_size)
        self.aspect1QLE.textChanged.connect(self.command_update_aspect)
        self.aspect2QLE.textChanged.connect(self.command_update_aspect)
        self.frameQLE.textChanged.connect(self.command_update_frames)
        self.bitrateQLE.textChanged.connect(self.command_update_vidbitrate)
        self.threadsQLE.textChanged.connect(self.command_update_threads)
        self.beginQLE.textChanged.connect(self.command_update_begin_time)
        self.durationQLE.textChanged.connect(self.command_update_duration)
        self.embedQLE.textChanged.connect(self.command_update_subtitles)
        self.vidcodecQCB.currentIndexChanged.connect(self.command_update_vcodec)
        self.audcodecQCB.currentIndexChanged.connect(self.command_update_acodec)
        self.freqQCB.currentIndexChanged.connect(self.command_update_frequency)
        self.rotateQCB.currentIndexChanged.connect(self.command_update_rotation)
        self.audbitrateQCB.currentIndexChanged.connect(self.command_update_audbitrate)
        self.chan1QRB.clicked.connect(lambda: self.command_update_channels("1"))
        self.chan2QRB.clicked.connect(lambda: self.command_update_channels("2"))
        self.preserveaspectQChB.toggled.connect(self.command_update_preserve_aspect)
        self.preservesizeQChB.toggled.connect(self.command_update_preserve_size)

    def resize_parent(self):
        """Give MainWindow its default size."""
        self.parent.setMinimumSize(self.parent.sizeHint())
        self.parent.resize(self.parent.sizeHint())

    def clear(self):
        """Clear all values of graphical widgets."""
        lines = [
            self.commandQLE,
            self.widthQLE,
            self.heightQLE,
            self.aspect1QLE,
            self.aspect2QLE,
            self.frameQLE,
            self.bitrateQLE,
            self.threadsQLE,
            self.beginQLE,
            self.embedQLE,
            self.durationQLE,
        ]
        for i in lines:
            i.clear()

        self.vidcodecQCB.setCurrentIndex(0)
        self.audcodecQCB.setCurrentIndex(0)
        self.freqQCB.setCurrentIndex(0)
        self.audbitrateQCB.setCurrentIndex(0)
        self.rotateQCB.setCurrentIndex(0)
        self.preserveaspectQChB.setChecked(False)
        self.preservesizeQChB.setChecked(False)
        self.group.setExclusive(False)
        self.chan1QRB.setChecked(False)
        self.chan2QRB.setChecked(False)
        self.group.setExclusive(True)
        # setExclusive(False) in order to be able to uncheck checkboxes and
        # then setExclusive(True) so only one radio button can be set

    def fill_video_comboboxes(self, vcodecs, acodecs, extraformats):
        vcodecs = [i for i in vcodecs.split("\n")] if vcodecs else []
        acodecs = [i for i in acodecs.split("\n")] if acodecs else []
        extraformats = [i for i in extraformats.split("\n")] if extraformats else []

        self.vidcodecQCB.currentIndexChanged.disconnect()
        self.audcodecQCB.currentIndexChanged.disconnect()

        self.vidcodecQCB.clear()
        self.audcodecQCB.clear()
        self.extQCB.clear()
        self.vidcodecQCB.addItems([self.defaultStr, self.DisableStream] + vcodecs)
        self.audcodecQCB.addItems([self.defaultStr, self.DisableStream] + acodecs)
        self.extQCB.addItems(sorted(self.formats + extraformats))

        self.vidcodecQCB.currentIndexChanged.connect(self.command_update_vcodec)
        self.audcodecQCB.currentIndexChanged.connect(self.command_update_acodec)

    def ok_to_continue(self):
        """
        Check if everything is ok with audiovideotab to continue conversion.

        Check if:
        - Either ffmpeg or avconv are installed.

        Return True if all tests pass, else False.
        """
        if self.parent.vidconverter is None:
            QMessageBox.warning(
                self,
                "FF Multi Converter - " + self.tr("Error!"),
                self.tr(
                    "Neither ffmpeg nor libav are installed."
                    "\nYou will not be able to convert audio/video files until you"
                    " install one of them."
                ),
            )
            return False
        return True

    def open_subtitle_file(self):
        """
        Get the filename using standard QtDialog and update embedQLE's text.
        """
        fname = QFileDialog.getOpenFileName(
            self, "FF Multi Converter - " + self.tr("Choose File"), config.home, "Subtitles (*.srt *.sub *.ssa *.ass)"
        )
        if fname:
            self.embedQLE.setText(fname)

    def set_default_command(self):
        """Set the default value to self.commandQLE."""
        self.clear()
        self.commandQLE.setText(self.parent.default_command)

    def choose_preset(self):
        """
        Open the presets dialog and update self.commandQLE,
        and self.extQCB and with the appropriate values.
        """
        dialog = presets_dlgs.ShowPresets(choose=True)
        if dialog.exec_() and dialog.the_command is not None:
            self.clear()
            self.commandQLE.setText(dialog.the_command)
            self.commandQLE.home(False)
            find = self.extQCB.findText(dialog.the_extension)
            if find >= 0:
                self.extQCB.setCurrentIndex(find)

    def command_update_size(self):
        command = self.commandQLE.text()
        text1 = self.widthQLE.text()
        text2 = self.heightQLE.text()

        if not (text1 == "-1" or text2 == "-1"):
            self.preserveaspectQChB.setChecked(False)

        if (text1 or text2) and not (text1 and text2) or (text1 == "-" or text2 == "-"):
            return

        regex = r"(\s+|^)-s(:v){0,1}\s+\d+x\d+(\s+|$)"
        if re.search(regex, command):
            command = re.sub(regex, "", command)

        regex = r"(,*\s*){0,1}(scale=-?\d+:-?\d+)(\s*,*\s*){0,1}"
        _filter = "scale={0}:{1}".format(text1, text2) if text1 and text2 else ""

        self.commandQLE.setText(utils.update_cmdline_text(command, _filter, regex, bool(text1 and text2), 0, 2))

    def command_update_preserve_size(self):
        checked = self.preservesizeQChB.isChecked()

        self.widthQLE.setEnabled(not checked)
        self.heightQLE.setEnabled(not checked)

        if checked:
            self.widthQLE.clear()
            self.heightQLE.clear()
            # command_update_size() is triggered here

        command = self.commandQLE.text()
        regex = r"(\s+|^)-s\s+\d+x\d+(\s+|$)"
        command = re.sub(" +", " ", re.sub(regex, " ", command)).strip()
        self.commandQLE.setText(command)

    def command_update_aspect(self):
        command = self.commandQLE.text()
        text1 = self.aspect1QLE.text()
        text2 = self.aspect2QLE.text()

        if (text1 or text2) and not (text1 and text2):
            return

        regex = r"(\s+|^)-aspect\s+\d+:\d+(\s+|$)"
        s = " -aspect {0}:{1} ".format(text1, text2) if text1 and text2 else " "

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(" +", " ", command).strip()
        self.commandQLE.setText(command)

    def command_update_preserve_aspect(self):
        command = self.commandQLE.text()
        checked = self.preserveaspectQChB.isChecked()

        self.aspect1QLE.setEnabled(not checked)
        self.aspect2QLE.setEnabled(not checked)

        if checked:
            self.aspect1QLE.clear()
            self.aspect2QLE.clear()
            # self.command_update_aspect() is triggered here

            regex = r"(,*\s*){0,1}(scale=(-?\d+):(-?\d+))(\s*,*\s*){0,1}"
            search = re.search(regex, command)
            if search:
                width = search.groups()[2]
                height = search.groups()[3]
                if not (width == "-1" or height == "-1"):
                    s = "scale=-1:{0}".format(height)
                    command = re.sub(regex, r"\1{0}\5".format(s), command)
                    self.widthQLE.setText("-1")
                    self.heightQLE.setText(height)

        regex = r"(\s+|^)-aspect\s+\d+:\d+(\s+|$)"
        command = re.sub(" +", " ", re.sub(regex, " ", command)).strip()
        self.commandQLE.setText(command)

    def command_update_frames(self):
        command = self.commandQLE.text()
        text = self.frameQLE.text()

        regex = r"(\s+|^)-r\s+\d+(\s+|$)"
        s = " -r {0} ".format(text) if text else " "

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(" +", " ", command).strip()
        self.commandQLE.setText(command)

    def command_update_vidbitrate(self):
        command = self.commandQLE.text()
        text = self.bitrateQLE.text()

        regex = r"(\s+|^)-b(:v){0,1}\s+\d+[kKmM](\s+|$)"
        s = " -b:v {0}k ".format(text) if text else " "

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub("-sameq", "", command)
        command = re.sub(" +", " ", command).strip()

        self.commandQLE.setText(command)

    def command_update_frequency(self):
        command = self.commandQLE.text()
        text = self.freqQCB.currentText()

        regex = r"(\s+|^)-ar\s+\d+(\s+|$)"
        s = " -ar {0} ".format(text) if self.freqQCB.currentIndex() != 0 else " "

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(" +", " ", command).strip()
        self.commandQLE.setText(command)

    def command_update_audbitrate(self):
        command = self.commandQLE.text()
        text = self.audbitrateQCB.currentText()

        regex = r"(\s+|^)-(ab|b:a)\s+\d+[kKmM](\s+|$)"
        if self.audbitrateQCB.currentIndex() != 0:
            s = " -b:a {0}k ".format(text)
        else:
            s = " "

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(" +", " ", command).strip()
        self.commandQLE.setText(command)

    def command_update_channels(self, channel):
        command = self.commandQLE.text()

        regex = r"(\s+|^)-ac\s+\d+(\s+|$)"
        s = " -ac {0} ".format(channel)

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(" +", " ", command).strip()
        self.commandQLE.setText(command)

    def command_update_threads(self):
        command = self.commandQLE.text()
        text = self.threadsQLE.text()

        regex = r"(\s+|^)-threads\s+\d+(\s+|$)"
        s = " -threads {0} ".format(text) if text else " "

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(" +", " ", command).strip()
        self.commandQLE.setText(command)

    def command_update_begin_time(self):
        command = self.commandQLE.text()
        text = self.beginQLE.text()

        regex = r"(\s+|^)-ss\s+\S+(\s+|$)"
        s = " -ss {0} ".format(text) if text else " "

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(" +", " ", command).strip()
        self.commandQLE.setText(command)

    def command_update_duration(self):
        command = self.commandQLE.text()
        text = self.durationQLE.text()

        regex = r"(\s+|^)-t\s+\S+(\s+|$)"
        s = " -t {0} ".format(text) if text else " "

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(" +", " ", command).strip()
        self.commandQLE.setText(command)

    def command_update_vcodec(self):
        command = self.commandQLE.text()
        text = self.vidcodecQCB.currentText()

        regex = r"(\s+|^)-(vcodec|c:v)\s+\S+(\s+|$)"
        regex_vn = r"(\s+|^)-vn(\s+|$)"
        if self.vidcodecQCB.currentIndex() == 1:
            s = " -vn ".format(text)
        elif self.vidcodecQCB.currentIndex() == 0:
            s = " "
        else:
            s = " -vcodec {0} ".format(text)

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        elif re.search(regex_vn, command):
            command = re.sub(regex_vn, s, command)
        else:
            command += s

        command = re.sub(" +", " ", command).strip()
        self.commandQLE.setText(command)

    def command_update_acodec(self):
        command = self.commandQLE.text()
        text = self.audcodecQCB.currentText()

        regex = r"(\s+|^)-(acodec|c:a)\s+\S+(\s+|$)"
        regex_an = r"(\s+|^)-an(\s+|$)"
        if self.audcodecQCB.currentIndex() == 1:
            s = " -an ".format(text)
        elif self.audcodecQCB.currentIndex() == 0:
            s = " "
        else:
            s = " -acodec {0} ".format(text)

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        elif re.search(regex_an, command):
            command = re.sub(regex_an, s, command)
        else:
            command += s

        command = re.sub(" +", " ", command).strip()
        self.commandQLE.setText(command)

    def command_update_subtitles(self):
        command = self.commandQLE.text()
        regex = r"(,*\s*){0,1}(subtitles=\'.*\')(\s*,*\s*){0,1}"

        text = self.embedQLE.text()
        _filter = "subtitles='{0}'".format(text) if text else ""

        self.commandQLE.setText(utils.update_cmdline_text(command, _filter, regex, bool(text), 0, 2))

    def command_update_rotation(self):
        command = self.commandQLE.text()
        regex = r"(,*\s*){0,1}(transpose=\d(,\s*transpose=\d)*|vflip|hflip)(\s*,*\s*){0,1}"

        rotate = self.rotateQCB.currentIndex()
        if rotate == 0:  # none
            _filter = ""
        elif rotate == 1:  # 90 clockwise
            _filter = "transpose=1"
        elif rotate == 2:  # 90 clockwise + vertical flip
            _filter = "transpose=3"
        elif rotate == 3:  # 90 counter clockwise
            _filter = "transpose=2"
        elif rotate == 4:  # 90 counter clockwise + vertical flip
            _filter = "transpose=0"
        elif rotate == 5:  # 180
            _filter = "transpose=2,transpose=2"
        elif rotate == 6:  # horizontal flip
            _filter = "hflip"
        elif rotate == 7:  # vertical flip
            _filter = "vflip"

        self.commandQLE.setText(utils.update_cmdline_text(command, _filter, regex, bool(rotate != 0), 0, 3))
Ejemplo n.º 4
0
class AudioVideoTab(QWidget):
    def __init__(self, parent):
        super(AudioVideoTab, self).__init__(parent)
        self.parent = parent
        self.name = 'AudioVideo'
        self.formats = ['3gp', 'aac', 'ac3', 'afc', 'aiff', 'amr', 'asf', 'au',
                        'avi', 'dvd', 'flac', 'flv', 'mka', 'mkv', 'mmf',
                        'mov', 'mp3', 'mp4', 'mpg', 'ogg', 'ogv', 'psp', 'rm',
                        'spx', 'vob', 'wav', 'webm', 'wma', 'wmv']
        self.extra_formats = ['aifc', 'm2t', 'm4a', 'm4v', 'mp2', 'mpeg',
                              'ra', 'ts']

        nochange = self.tr('No Change')
        frequency_values = [nochange, '22050', '44100', '48000']
        bitrate_values = [nochange, '32', '96', '112', '128', '160', '192',
                          '256', '320']
        pattern = QRegExp(r'^[1-9]\d*')
        validator = QRegExpValidator(pattern, self)

        converttoLabel = QLabel(self.tr('Convert to:'))
        self.extComboBox = QComboBox()
        self.extComboBox.addItems(self.formats + [self.tr('Other')])
        self.extComboBox.setMinimumWidth(130)
        self.extLineEdit = QLineEdit()
        self.extLineEdit.setMaximumWidth(85)
        self.extLineEdit.setEnabled(False)
        hlayout1 = pyqttools.add_to_layout(QHBoxLayout(), converttoLabel,
                                           None, self.extComboBox,
                                           self.extLineEdit)
        commandLabel = QLabel(self.tr('Command:'))
        self.commandLineEdit = QLineEdit()
        self.presetButton = QPushButton(self.tr('Preset'))
        self.defaultButton = QPushButton(self.tr('Default'))
        hlayout2 = pyqttools.add_to_layout(QHBoxLayout(), commandLabel,
                                       self.commandLineEdit, self.presetButton,
                                       self.defaultButton)

        sizeLabel = QLabel(self.tr('Video Size:'))
        aspectLabel = QLabel(self.tr('Aspect:'))
        frameLabel = QLabel(self.tr('Frame Rate (fps):'))
        bitrateLabel = QLabel(self.tr('Video Bitrate (kbps):'))

        self.widthLineEdit = pyqttools.create_LineEdit((50, 16777215),
                                                       validator, 4)
        self.heightLineEdit = pyqttools.create_LineEdit((50, 16777215),
                                                        validator,4)
        label = QLabel('x')
        layout1 = pyqttools.add_to_layout(QHBoxLayout(), self.widthLineEdit,
                                          label, self.heightLineEdit)
        self.aspect1LineEdit = pyqttools.create_LineEdit((35, 16777215),
                                                         validator,2)
        self.aspect2LineEdit = pyqttools.create_LineEdit((35, 16777215),
                                                         validator,2)
        label = QLabel(':')
        layout2 = pyqttools.add_to_layout(QHBoxLayout(), self.aspect1LineEdit,
                                          label, self.aspect2LineEdit)
        self.frameLineEdit = pyqttools.create_LineEdit(None, validator, 4)
        self.bitrateLineEdit = pyqttools.create_LineEdit(None, validator, 6)

        labels = [sizeLabel, aspectLabel, frameLabel, bitrateLabel]
        widgets = [layout1, layout2, self.frameLineEdit, self.bitrateLineEdit]

        videosettings_layout = QHBoxLayout()
        for a, b in zip(labels, widgets):
            text = a.text()
            a.setText('<html><p align="center">{0}</p></html>'.format(text))
            layout = pyqttools.add_to_layout(QVBoxLayout(), a, b)
            videosettings_layout.addLayout(layout)

        freqLabel = QLabel(self.tr('Frequency (Hz):'))
        chanLabel = QLabel(self.tr('Channels:'))
        bitrateLabel = QLabel(self.tr('Audio Bitrate (kbps):'))

        self.freqComboBox = QComboBox()
        self.freqComboBox.addItems(frequency_values)
        self.chan1RadioButton = QRadioButton('1')
        self.chan1RadioButton.setMaximumSize(QSize(51, 16777215))
        self.chan2RadioButton = QRadioButton('2')
        self.chan2RadioButton.setMaximumSize(QSize(51, 16777215))
        self.group = QButtonGroup()
        self.group.addButton(self.chan1RadioButton)
        self.group.addButton(self.chan2RadioButton)
        spcr1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)
        spcr2 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)
        chanlayout = pyqttools.add_to_layout(QHBoxLayout(), spcr1,
                                             self.chan1RadioButton,
                                             self.chan2RadioButton, spcr2)
        self.audio_bitrateComboBox = QComboBox()
        self.audio_bitrateComboBox.addItems(bitrate_values)

        labels = [freqLabel, chanLabel, bitrateLabel]
        widgets = [self.freqComboBox, chanlayout, self.audio_bitrateComboBox]

        audiosettings_layout = QHBoxLayout()
        for a, b in zip(labels, widgets):
            text = a.text()
            a.setText('<html><p align="center">{0}</p></html>'.format(text))
            layout = pyqttools.add_to_layout(QVBoxLayout(), a, b)
            audiosettings_layout.addLayout(layout)

        hidden_layout = pyqttools.add_to_layout(QVBoxLayout(),
                                                videosettings_layout,
                                                audiosettings_layout)

        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.moreButton = QPushButton(QApplication.translate('Tab', 'More'))
        self.moreButton.setSizePolicy(QSizePolicy(QSizePolicy.Fixed))
        self.moreButton.setCheckable(True)
        hlayout3 = pyqttools.add_to_layout(QHBoxLayout(), line, self.moreButton)

        self.frame = QFrame()
        self.frame.setLayout(hidden_layout)
        self.frame.hide()

        final_layout = pyqttools.add_to_layout(QVBoxLayout(), hlayout1,
                                               hlayout2, hlayout3, self.frame)
        self.setLayout(final_layout)


        self.presetButton.clicked.connect(self.choose_preset)
        self.defaultButton.clicked.connect(self.set_default_command)
        self.moreButton.toggled.connect(self.frame.setVisible)
        self.moreButton.toggled.connect(self.resize_parent)
        self.extComboBox.currentIndexChanged.connect(
                lambda: self.extLineEdit.setEnabled(
                self.extComboBox.currentIndex() == len(self.formats)))
        self.widthLineEdit.textChanged.connect(
                lambda: self.command_elements_change('size'))
        self.heightLineEdit.textChanged.connect(
                lambda: self.command_elements_change('size'))
        self.aspect1LineEdit.textChanged.connect(
                lambda: self.command_elements_change('aspect'))
        self.aspect2LineEdit.textChanged.connect(
                lambda: self.command_elements_change('aspect'))
        self.frameLineEdit.textChanged.connect(
                lambda: self.command_elements_change('frames'))
        self.bitrateLineEdit.textChanged.connect(
                lambda: self.command_elements_change('video_bitrate'))
        self.freqComboBox.currentIndexChanged.connect(
                lambda: self.command_elements_change('frequency'))
        self.audio_bitrateComboBox.currentIndexChanged.connect(
                lambda: self.command_elements_change('audio_bitrate'))
        self.chan1RadioButton.clicked.connect(
                lambda: self.command_elements_change('channels1'))
        self.chan2RadioButton.clicked.connect(
                lambda: self.command_elements_change('channels2'))

    def resize_parent(self):
        """Resize MainWindow."""
        height = MAIN_FIXED_HEIGHT if self.frame.isVisible() else MAIN_HEIGHT
        self.parent.setMinimumSize(MAIN_WIDTH, height)
        self.parent.resize(MAIN_WIDTH, height)

    def clear(self):
        """Clear all values of graphical widgets."""
        lines = [self.commandLineEdit, self.widthLineEdit, self.heightLineEdit,
                 self.aspect1LineEdit, self.aspect2LineEdit, self.frameLineEdit,
                 self.bitrateLineEdit, self.extLineEdit]
        for i in lines:
            i.clear()

        self.freqComboBox.setCurrentIndex(0)
        self.audio_bitrateComboBox.setCurrentIndex(0)
        self.group.setExclusive(False)
        self.chan1RadioButton.setChecked(False)
        self.chan2RadioButton.setChecked(False)
        self.group.setExclusive(True)
        # setExclusive(False) in order to be able to uncheck checkboxes and
        # then setExclusive(True) so only one radio button can be set

    def ok_to_continue(self):
        """
        Check if everything is ok with audiovideotab to continue conversion.

        Check if:
        - Either ffmpeg or avconv are installed.
        - Desired extension is valid.
        - self.commandLineEdit is empty.

        Return True if all tests pass, else False.
        """
        if not self.parent.ffmpeg and not self.parent.avconv:
            QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr(
                'Error!'), self.tr('Neither ffmpeg nor avconv are installed.'
                '\nYou will not be able to convert audio/video files until you'
                ' install one of them.'))
            return False
        if self.extLineEdit.isEnabled():
            text = str(self.extLineEdit.text()).strip()
            if len(text.split()) != 1 or text[0] == '.':
                QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr(
                    'Error!'), self.tr('Extension must be one word and must '
                    'not start with a dot.'))
                self.extLineEdit.selectAll()
                self.extLineEdit.setFocus()
                return False
        if not self.commandLineEdit.text():
            QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr(
                  'Error!'), self.tr('The command LineEdit may not be empty.'))
            self.commandLineEdit.setFocus()
            return False
        return True

    def set_default_command(self):
        """Set the default value to self.commandLineEdit."""
        self.clear()
        self.commandLineEdit.setText(self.parent.default_command)

    def choose_preset(self):
        """
        Open the presets dialog and update self.commandLineEdit,
        self.extComboBox and self.extLineEdit with the appropriate values.
        """
        dialog = presets_dlgs.ShowPresets()
        if dialog.exec_() and dialog.the_command is not None:
            self.commandLineEdit.setText(dialog.the_command)
            self.commandLineEdit.home(False)
            find = self.extComboBox.findText(dialog.the_extension)
            if find >= 0:
                self.extComboBox.setCurrentIndex(find)
            else:
                self.extComboBox.setCurrentIndex(len(self.formats))
                self.extLineEdit.setText(dialog.the_extension)

    def remove_consecutive_spaces(self, string):
        """Remove any consecutive spaces from a string and return it."""
        temp = string
        string = ''
        for i in temp.split():
            if i:
                string += i + ' '
        return string[:-1]

    def command_elements_change(self, widget):
        """Fill self.commandLineEdit with the appropriate command parameters."""
        command = str(self.commandLineEdit.text())

        if widget == 'size':
            text1 = self.widthLineEdit.text()
            text2 = self.heightLineEdit.text()

            if (text1 or text2) and not (text1 and text2):
                return
            f = re.sub(r'^.*(-s\s+\d+x\d+).*$', r'\1', command)
            if re.match(r'^.*(-s\s+\d+x\d+).*$', f):
                command = command.replace(f, '').strip()
            if text1 and text2:
                command += ' -s {0}x{1}'.format(text1, text2)

        elif widget == 'aspect':
            text1 = self.aspect1LineEdit.text()
            text2 = self.aspect2LineEdit.text()

            if (text1 or text2) and not (text1 and text2):
                return
            f = re.sub(r'^.*(-aspect\s+\d+:\d+).*$', r'\1', command)
            if re.match(r'^.*(-aspect\s+\d+:\d+).*$', f):
                command = command.replace(f, '').strip()
            if text1 and text2:
                command += ' -aspect {0}:{1}'.format(text1, text2)

        elif widget == 'frames':
            text = self.frameLineEdit.text()
            f = re.sub(r'^.*(-r\s+\d+).*$', r'\1', command)
            if re.match(r'^.*(-r\s+\d+).*$', f):
                command = command.replace(f, '').strip()
            if text:
                command += ' -r {0}'.format(text)

        elif widget == 'video_bitrate':
            text = self.bitrateLineEdit.text()
            f = re.sub(r'^.*(-b\s+\d+k).*$', r'\1', command)
            if re.match(r'^.*(-b\s+\d+k).*$', f):
                command = command.replace(f, '')
            if text:
                command += ' -b {0}k'.format(text)
            command = command.replace('-sameq', '').strip()

        elif widget == 'frequency':
            text = self.freqComboBox.currentText()
            f = re.sub(r'^.*(-ar\s+\d+).*$', r'\1', command)
            if re.match(r'^.*(-ar\s+\d+).*$', f):
                command = command.replace(f, '').strip()
            if text != 'No Change':
                command += ' -ar {0}'.format(text)

        elif widget == 'audio_bitrate':
            text = self.audio_bitrateComboBox.currentText()
            f = re.sub(r'^.*(-ab\s+\d+k).*$', r'\1', command)
            if re.match(r'^.*(-ab\s+\d+k).*$', f):
                command = command.replace(f, '').strip()
            if text != 'No Change':
                command += ' -ab {0}k'.format(text)

        elif widget in ('channels1', 'channels2'):
            text = self.chan1RadioButton.text() if widget == 'channels1' \
                                            else self.chan2RadioButton.text()
            f = re.sub(r'^.*(-ac\s+\d+).*$', r'\1', command)
            if re.match(r'^.*(-ac\s+\d+).*$', f):
                command = command.replace(f, '').strip()
            command += ' -ac {0}'.format(text)

        self.commandLineEdit.clear()
        self.commandLineEdit.setText(self.remove_consecutive_spaces(command))
class AudioVideoTab(QWidget):
    def __init__(self, parent):
        super(AudioVideoTab, self).__init__(parent)
        self.parent = parent
        self.name = 'AudioVideo'

        self.defaultStr = self.tr('Default')
        self.DisableStream = self.tr('Disable')

        self.formats = config.video_formats
        frequency_values = [self.defaultStr] + config.video_frequency_values
        bitrate_values = [self.defaultStr] + config.video_bitrate_values

        rotation_options = [
            self.tr('None'), '90 ' + self.tr('clockwise'),
            '90 ' + self.tr('clockwise') + ' + ' + self.tr('vertical flip'),
            '90 ' + self.tr('counter clockwise'), '90 ' +
            self.tr('counter clockwise') + ' + ' + self.tr('vertical flip'),
            '180',
            self.tr('horizontal flip'),
            self.tr('vertical flip')
        ]

        digits_validator = QRegExpValidator(QRegExp(r'[1-9]\d*'), self)
        digits_validator_wzero = QRegExpValidator(QRegExp(r'\d*'), self)
        digits_validator_minus = QRegExpValidator(QRegExp(r'(-1|[1-9]\d*)'),
                                                  self)
        time_validator = QRegExpValidator(
            QRegExp(r'\d{1,2}:\d{1,2}:\d{1,2}\.\d+'), self)

        converttoQL = QLabel(self.tr('Convert to:'))
        self.extQCB = QComboBox()
        self.extQCB.setMinimumWidth(100)
        vidcodecQL = QLabel('Video codec:')
        self.vidcodecQCB = QComboBox()
        self.vidcodecQCB.setMinimumWidth(110)
        audcodecQL = QLabel('Audio codec:')
        self.audcodecQCB = QComboBox()
        self.audcodecQCB.setMinimumWidth(110)

        hlayout1 = utils.add_to_layout('h', converttoQL, self.extQCB,
                                       QSpacerItem(180, 20), vidcodecQL,
                                       self.vidcodecQCB, audcodecQL,
                                       self.audcodecQCB)

        commandQL = QLabel(self.tr('Command:'))
        self.commandQLE = QLineEdit()
        self.presetQPB = QPushButton(self.tr('Preset'))
        self.defaultQPB = QPushButton(self.defaultStr)
        hlayout2 = utils.add_to_layout('h', commandQL, self.commandQLE,
                                       self.presetQPB, self.defaultQPB)

        sizeQL = QLabel(self.tr('Video Size:'))
        aspectQL = QLabel(self.tr('Aspect:'))
        frameQL = QLabel(self.tr('Frame Rate (fps):'))
        bitrateQL = QLabel(self.tr('Video Bitrate (kbps):'))

        self.widthQLE = utils.create_LineEdit((70, 16777215),
                                              digits_validator_minus, 4)
        self.heightQLE = utils.create_LineEdit((70, 16777215),
                                               digits_validator_minus, 4)
        label = QLabel('<html><p align="center">x</p></html>')
        layout1 = utils.add_to_layout('h', self.widthQLE, label,
                                      self.heightQLE)
        self.aspect1QLE = utils.create_LineEdit((50, 16777215),
                                                digits_validator, 2)
        self.aspect2QLE = utils.create_LineEdit((50, 16777215),
                                                digits_validator, 2)
        label = QLabel('<html><p align="center">:</p></html>')
        layout2 = utils.add_to_layout('h', self.aspect1QLE, label,
                                      self.aspect2QLE)
        self.frameQLE = utils.create_LineEdit((120, 16777215),
                                              digits_validator, 4)
        self.bitrateQLE = utils.create_LineEdit((130, 16777215),
                                                digits_validator, 6)

        labels = [sizeQL, aspectQL, frameQL, bitrateQL]
        widgets = [layout1, layout2, self.frameQLE, self.bitrateQLE]

        self.preserveaspectQChB = QCheckBox(self.tr("Preserve aspect ratio"))
        self.preservesizeQChB = QCheckBox(self.tr("Preserve video size"))

        preserve_layout = utils.add_to_layout('v', self.preserveaspectQChB,
                                              self.preservesizeQChB)

        videosettings_layout = QHBoxLayout()
        for a, b in zip(labels, widgets):
            a.setText('<html><p align="center">{0}</p></html>'.format(
                a.text()))
            layout = utils.add_to_layout('v', a, b)
            videosettings_layout.addLayout(layout)
            if a == aspectQL:
                # add vidaspectCB in layout after aspectQL
                videosettings_layout.addLayout(preserve_layout)

        freqQL = QLabel(self.tr('Frequency (Hz):'))
        chanQL = QLabel(self.tr('Audio Channels:'))
        bitrateQL = QLabel(self.tr('Audio Bitrate (kbps):'))
        threadsQL = QLabel(self.tr('Threads:'))

        self.freqQCB = QComboBox()
        self.freqQCB.addItems(frequency_values)
        self.chan1QRB = QRadioButton('1')
        self.chan1QRB.setMaximumSize(QSize(51, 16777215))
        self.chan2QRB = QRadioButton('2')
        self.chan2QRB.setMaximumSize(QSize(51, 16777215))
        self.group = QButtonGroup()
        self.group.addButton(self.chan1QRB)
        self.group.addButton(self.chan2QRB)
        spcr1 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)
        spcr2 = QSpacerItem(40, 20, QSizePolicy.Preferred, QSizePolicy.Minimum)
        chanlayout = utils.add_to_layout('h', spcr1, self.chan1QRB,
                                         self.chan2QRB, spcr2)
        self.audbitrateQCB = QComboBox()
        self.audbitrateQCB.addItems(bitrate_values)
        self.threadsQLE = utils.create_LineEdit((50, 16777215),
                                                digits_validator_wzero, 1)

        labels = [freqQL, bitrateQL, chanQL, threadsQL]
        widgets = [
            self.freqQCB, self.audbitrateQCB, chanlayout, self.threadsQLE
        ]

        audiosettings_layout = QHBoxLayout()
        for a, b in zip(labels, widgets):
            a.setText('<html><p align="center">{0}</p></html>'.format(
                a.text()))
            layout = utils.add_to_layout('v', a, b)
            audiosettings_layout.addLayout(layout)

        time_format = " (hh:mm:ss):"
        beginQL = QLabel(self.tr("Split file. Begin time") + time_format)
        self.beginQLE = utils.create_LineEdit(None, time_validator, None)
        durationQL = QLabel(self.tr("Duration") + time_format)
        self.durationQLE = utils.create_LineEdit(None, time_validator, None)

        hlayout4 = utils.add_to_layout('h', beginQL, self.beginQLE, durationQL,
                                       self.durationQLE)

        embedQL = QLabel(self.tr("Embed subtitle:"))
        self.embedQLE = QLineEdit()
        self.embedQTB = QToolButton()
        self.embedQTB.setText("...")

        rotateQL = QLabel(self.tr("Rotate:"))
        self.rotateQCB = QComboBox()
        self.rotateQCB.addItems(rotation_options)

        hlayout5 = utils.add_to_layout('h', rotateQL, self.rotateQCB, embedQL,
                                       self.embedQLE, self.embedQTB)

        hidden_layout = utils.add_to_layout('v', videosettings_layout,
                                            audiosettings_layout, hlayout4,
                                            hlayout5)

        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.moreQPB = QPushButton(QApplication.translate('Tab', 'More'))
        self.moreQPB.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.moreQPB.setCheckable(True)
        hlayout3 = utils.add_to_layout('h', line, self.moreQPB)

        self.frame = QFrame()
        self.frame.setLayout(hidden_layout)
        self.frame.hide()

        final_layout = utils.add_to_layout('v', hlayout1, hlayout2, hlayout3,
                                           self.frame)
        self.setLayout(final_layout)

        self.presetQPB.clicked.connect(self.choose_preset)
        self.defaultQPB.clicked.connect(self.set_default_command)
        self.embedQTB.clicked.connect(self.open_subtitle_file)
        self.moreQPB.toggled.connect(self.frame.setVisible)
        self.moreQPB.toggled.connect(
            lambda: QTimer.singleShot(100, self.resize_parent))
        self.widthQLE.textChanged.connect(self.command_update_size)
        self.heightQLE.textChanged.connect(self.command_update_size)
        self.aspect1QLE.textChanged.connect(self.command_update_aspect)
        self.aspect2QLE.textChanged.connect(self.command_update_aspect)
        self.frameQLE.textChanged.connect(self.command_update_frames)
        self.bitrateQLE.textChanged.connect(self.command_update_vidbitrate)
        self.threadsQLE.textChanged.connect(self.command_update_threads)
        self.beginQLE.textChanged.connect(self.command_update_begin_time)
        self.durationQLE.textChanged.connect(self.command_update_duration)
        self.embedQLE.textChanged.connect(self.command_update_subtitles)
        self.vidcodecQCB.currentIndexChanged.connect(
            self.command_update_vcodec)
        self.audcodecQCB.currentIndexChanged.connect(
            self.command_update_acodec)
        self.freqQCB.currentIndexChanged.connect(self.command_update_frequency)
        self.rotateQCB.currentIndexChanged.connect(
            self.command_update_rotation)
        self.audbitrateQCB.currentIndexChanged.connect(
            self.command_update_audbitrate)
        self.chan1QRB.clicked.connect(
            lambda: self.command_update_channels('1'))
        self.chan2QRB.clicked.connect(
            lambda: self.command_update_channels('2'))
        self.preserveaspectQChB.toggled.connect(
            self.command_update_preserve_aspect)
        self.preservesizeQChB.toggled.connect(
            self.command_update_preserve_size)

    def resize_parent(self):
        """Give MainWindow its default size."""
        self.parent.setMinimumSize(self.parent.sizeHint())
        self.parent.resize(self.parent.sizeHint())

    def clear(self):
        """Clear all values of graphical widgets."""
        lines = [
            self.commandQLE, self.widthQLE, self.heightQLE, self.aspect1QLE,
            self.aspect2QLE, self.frameQLE, self.bitrateQLE, self.threadsQLE,
            self.beginQLE, self.embedQLE, self.durationQLE
        ]
        for i in lines:
            i.clear()

        self.vidcodecQCB.setCurrentIndex(0)
        self.audcodecQCB.setCurrentIndex(0)
        self.freqQCB.setCurrentIndex(0)
        self.audbitrateQCB.setCurrentIndex(0)
        self.rotateQCB.setCurrentIndex(0)
        self.preserveaspectQChB.setChecked(False)
        self.preservesizeQChB.setChecked(False)
        self.group.setExclusive(False)
        self.chan1QRB.setChecked(False)
        self.chan2QRB.setChecked(False)
        self.group.setExclusive(True)
        # setExclusive(False) in order to be able to uncheck checkboxes and
        # then setExclusive(True) so only one radio button can be set

    def fill_video_comboboxes(self, vcodecs, acodecs, extraformats):
        vcodecs = [i for i in vcodecs.split("\n")] if vcodecs else []
        acodecs = [i for i in acodecs.split("\n")] if acodecs else []
        extraformats = [i for i in extraformats.split("\n")
                        ] if extraformats else []

        self.vidcodecQCB.currentIndexChanged.disconnect()
        self.audcodecQCB.currentIndexChanged.disconnect()

        self.vidcodecQCB.clear()
        self.audcodecQCB.clear()
        self.extQCB.clear()
        self.vidcodecQCB.addItems([self.defaultStr, self.DisableStream] +
                                  vcodecs)
        self.audcodecQCB.addItems([self.defaultStr, self.DisableStream] +
                                  acodecs)
        self.extQCB.addItems(sorted(self.formats + extraformats))

        self.vidcodecQCB.currentIndexChanged.connect(
            self.command_update_vcodec)
        self.audcodecQCB.currentIndexChanged.connect(
            self.command_update_acodec)

    def ok_to_continue(self):
        """
        Check if everything is ok with audiovideotab to continue conversion.

        Check if:
        - Either ffmpeg or avconv are installed.

        Return True if all tests pass, else False.
        """
        if self.parent.vidconverter is None:
            QMessageBox.warning(
                self, 'FF Multi Converter - ' + self.tr('Error!'),
                self.
                tr('Neither ffmpeg nor libav are installed.'
                   '\nYou will not be able to convert audio/video files until you'
                   ' install one of them.'))
            return False
        return True

    def open_subtitle_file(self):
        """
        Get the filename using standard QtDialog and update embedQLE's text.
        """
        fname = QFileDialog.getOpenFileName(
            self, 'FF Multi Converter - ' + self.tr('Choose File'),
            config.home, 'Subtitles (*.srt *.sub *.ssa *.ass)')
        if fname:
            self.embedQLE.setText(fname)

    def set_default_command(self):
        """Set the default value to self.commandQLE."""
        self.clear()
        self.commandQLE.setText(self.parent.default_command)

    def choose_preset(self):
        """
        Open the presets dialog and update self.commandQLE,
        and self.extQCB and with the appropriate values.
        """
        dialog = presets_dlgs.ShowPresets(choose=True)
        if dialog.exec_() and dialog.the_command is not None:
            self.clear()
            self.commandQLE.setText(dialog.the_command)
            self.commandQLE.home(False)
            find = self.extQCB.findText(dialog.the_extension)
            if find >= 0:
                self.extQCB.setCurrentIndex(find)

    def command_update_size(self):
        command = self.commandQLE.text()
        text1 = self.widthQLE.text()
        text2 = self.heightQLE.text()

        if not (text1 == '-1' or text2 == '-1'):
            self.preserveaspectQChB.setChecked(False)

        if (text1 or text2) and not (text1 and text2) or (text1 == '-'
                                                          or text2 == '-'):
            return

        regex = r'(\s+|^)-s(:v){0,1}\s+\d+x\d+(\s+|$)'
        if re.search(regex, command):
            command = re.sub(regex, '', command)

        regex = r'(,*\s*){0,1}(scale=-?\d+:-?\d+)(\s*,*\s*){0,1}'
        _filter = "scale={0}:{1}".format(text1,
                                         text2) if text1 and text2 else ''

        self.commandQLE.setText(
            utils.update_cmdline_text(command, _filter, regex,
                                      bool(text1 and text2), 0, 2))

    def command_update_preserve_size(self):
        checked = self.preservesizeQChB.isChecked()

        self.widthQLE.setEnabled(not checked)
        self.heightQLE.setEnabled(not checked)

        if checked:
            self.widthQLE.clear()
            self.heightQLE.clear()
            # command_update_size() is triggered here

        command = self.commandQLE.text()
        regex = r'(\s+|^)-s\s+\d+x\d+(\s+|$)'
        command = re.sub(' +', ' ', re.sub(regex, ' ', command)).strip()
        self.commandQLE.setText(command)

    def command_update_aspect(self):
        command = self.commandQLE.text()
        text1 = self.aspect1QLE.text()
        text2 = self.aspect2QLE.text()

        if (text1 or text2) and not (text1 and text2):
            return

        regex = r'(\s+|^)-aspect\s+\d+:\d+(\s+|$)'
        s = ' -aspect {0}:{1} '.format(text1,
                                       text2) if text1 and text2 else ' '

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(' +', ' ', command).strip()
        self.commandQLE.setText(command)

    def command_update_preserve_aspect(self):
        command = self.commandQLE.text()
        checked = self.preserveaspectQChB.isChecked()

        self.aspect1QLE.setEnabled(not checked)
        self.aspect2QLE.setEnabled(not checked)

        if checked:
            self.aspect1QLE.clear()
            self.aspect2QLE.clear()
            # self.command_update_aspect() is triggered here

            regex = r'(,*\s*){0,1}(scale=(-?\d+):(-?\d+))(\s*,*\s*){0,1}'
            search = re.search(regex, command)
            if search:
                width = search.groups()[2]
                height = search.groups()[3]
                if not (width == '-1' or height == '-1'):
                    s = "scale=-1:{0}".format(height)
                    command = re.sub(regex, r'\1{0}\5'.format(s), command)
                    self.widthQLE.setText('-1')
                    self.heightQLE.setText(height)

        regex = r'(\s+|^)-aspect\s+\d+:\d+(\s+|$)'
        command = re.sub(' +', ' ', re.sub(regex, ' ', command)).strip()
        self.commandQLE.setText(command)

    def command_update_frames(self):
        command = self.commandQLE.text()
        text = self.frameQLE.text()

        regex = r'(\s+|^)-r\s+\d+(\s+|$)'
        s = ' -r {0} '.format(text) if text else ' '

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(' +', ' ', command).strip()
        self.commandQLE.setText(command)

    def command_update_vidbitrate(self):
        command = self.commandQLE.text()
        text = self.bitrateQLE.text()

        regex = r'(\s+|^)-b(:v){0,1}\s+\d+[kKmM](\s+|$)'
        s = ' -b:v {0}k '.format(text) if text else ' '

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub('-sameq', '', command)
        command = re.sub(' +', ' ', command).strip()

        self.commandQLE.setText(command)

    def command_update_frequency(self):
        command = self.commandQLE.text()
        text = self.freqQCB.currentText()

        regex = r'(\s+|^)-ar\s+\d+(\s+|$)'
        s = ' -ar {0} '.format(
            text) if self.freqQCB.currentIndex() != 0 else ' '

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(' +', ' ', command).strip()
        self.commandQLE.setText(command)

    def command_update_audbitrate(self):
        command = self.commandQLE.text()
        text = self.audbitrateQCB.currentText()

        regex = r'(\s+|^)-(ab|b:a)\s+\d+[kKmM](\s+|$)'
        if self.audbitrateQCB.currentIndex() != 0:
            s = ' -b:a {0}k '.format(text)
        else:
            s = ' '

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(' +', ' ', command).strip()
        self.commandQLE.setText(command)

    def command_update_channels(self, channel):
        command = self.commandQLE.text()

        regex = r'(\s+|^)-ac\s+\d+(\s+|$)'
        s = ' -ac {0} '.format(channel)

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(' +', ' ', command).strip()
        self.commandQLE.setText(command)

    def command_update_threads(self):
        command = self.commandQLE.text()
        text = self.threadsQLE.text()

        regex = r'(\s+|^)-threads\s+\d+(\s+|$)'
        s = ' -threads {0} '.format(text) if text else ' '

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(' +', ' ', command).strip()
        self.commandQLE.setText(command)

    def command_update_begin_time(self):
        command = self.commandQLE.text()
        text = self.beginQLE.text()

        regex = r'(\s+|^)-ss\s+\S+(\s+|$)'
        s = ' -ss {0} '.format(text) if text else ' '

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(' +', ' ', command).strip()
        self.commandQLE.setText(command)

    def command_update_duration(self):
        command = self.commandQLE.text()
        text = self.durationQLE.text()

        regex = r'(\s+|^)-t\s+\S+(\s+|$)'
        s = ' -t {0} '.format(text) if text else ' '

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        else:
            command += s

        command = re.sub(' +', ' ', command).strip()
        self.commandQLE.setText(command)

    def command_update_vcodec(self):
        command = self.commandQLE.text()
        text = self.vidcodecQCB.currentText()

        regex = r'(\s+|^)-(vcodec|c:v)\s+\S+(\s+|$)'
        regex_vn = r'(\s+|^)-vn(\s+|$)'
        if self.vidcodecQCB.currentIndex() == 1:
            s = ' -vn '.format(text)
        elif self.vidcodecQCB.currentIndex() == 0:
            s = ' '
        else:
            s = ' -vcodec {0} '.format(text)

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        elif re.search(regex_vn, command):
            command = re.sub(regex_vn, s, command)
        else:
            command += s

        command = re.sub(' +', ' ', command).strip()
        self.commandQLE.setText(command)

    def command_update_acodec(self):
        command = self.commandQLE.text()
        text = self.audcodecQCB.currentText()

        regex = r'(\s+|^)-(acodec|c:a)\s+\S+(\s+|$)'
        regex_an = r'(\s+|^)-an(\s+|$)'
        if self.audcodecQCB.currentIndex() == 1:
            s = ' -an '.format(text)
        elif self.audcodecQCB.currentIndex() == 0:
            s = ' '
        else:
            s = ' -acodec {0} '.format(text)

        if re.search(regex, command):
            command = re.sub(regex, s, command)
        elif re.search(regex_an, command):
            command = re.sub(regex_an, s, command)
        else:
            command += s

        command = re.sub(' +', ' ', command).strip()
        self.commandQLE.setText(command)

    def command_update_subtitles(self):
        command = self.commandQLE.text()
        regex = r'(,*\s*){0,1}(subtitles=\'.*\')(\s*,*\s*){0,1}'

        text = self.embedQLE.text()
        _filter = "subtitles='{0}'".format(text) if text else ''

        self.commandQLE.setText(
            utils.update_cmdline_text(command, _filter, regex, bool(text), 0,
                                      2))

    def command_update_rotation(self):
        command = self.commandQLE.text()
        regex = r'(,*\s*){0,1}(transpose=\d(,\s*transpose=\d)*|vflip|hflip)(\s*,*\s*){0,1}'

        rotate = self.rotateQCB.currentIndex()
        if rotate == 0:  # none
            _filter = ''
        elif rotate == 1:  # 90 clockwise
            _filter = 'transpose=1'
        elif rotate == 2:  # 90 clockwise + vertical flip
            _filter = 'transpose=3'
        elif rotate == 3:  # 90 counter clockwise
            _filter = 'transpose=2'
        elif rotate == 4:  # 90 counter clockwise + vertical flip
            _filter = 'transpose=0'
        elif rotate == 5:  # 180
            _filter = 'transpose=2,transpose=2'
        elif rotate == 6:  # horizontal flip
            _filter = 'hflip'
        elif rotate == 7:  # vertical flip
            _filter = 'vflip'

        self.commandQLE.setText(
            utils.update_cmdline_text(command, _filter, regex,
                                      bool(rotate != 0), 0, 3))