Beispiel #1
0
    def run_process(self, dir, filename, set_item, childIndex):
        if self.p is None:  # No process running.
            self.p_item = dict(set_item=set_item, child_index=childIndex)
            self.p = QProcess(
            )  # Keep a reference to the QProcess (e.g. on self) while it's running.

            #    item
            #       self.p.readyReadStandardOutput.connect(self.handle_stdout)
            self.p.readyReadStandardError.connect(self.handle_stderr)
            self.p.stateChanged.connect(self.handle_state)
            self.p.finished.connect(
                self.process_finished)  # Clean up once complete.

            #   filename = r"J:\Media Library\TV\New\Family Guy\Misc\Family Guy S07E11.avi"

            filepath = dir + filename
            self.message("Executing process for file: " + filepath)

            if Path(filepath).stat().st_size > 0:
                args = ["-hashfile", filepath, "SHA512"]
                self.p.start("certutil", args)
            else:
                # CertUtil cannot compute hashes on empty files
                args = ["zero_sha512.py"]
                self.p.start("python", args)

            status = set_item.child(childIndex, 0)

            status.setIcon(self.running_icon)
            set_item.setIcon(self.running_icon)

            if status.text() == '':
                if set_item.text() != 'Test':
                    set_item.child(childIndex, 0).setText('Running Pass 1/3')
                else:
                    set_item.child(childIndex, 0).setText('Running')
            elif status.text() == 'Running Pass 1/3':
                set_item.child(childIndex, 0).setText('Running Pass 2/3')
            elif status.text() == 'Running Pass 2/3':
                set_item.child(childIndex, 0).setText('Running Pass 3/3')

        else:
            self.message("process already running!")
Beispiel #2
0
    def item_open_event(self):
        """
        Opens the selected files using xdg-open, runs it, if it is executable
        or changes the current dir if it's dir.
        """
        selected_items = []
        for index in self.table_view.selectedIndexes():
            if index.column() == 0:
                selected_items.append(QFileInfo(os.path.join(self.current_path,
                                      index.siblingAtColumn(0).data())))

        # warn before accidentally open a bunch of files
        open = True
        if len(selected_items) > 3:
            dialog = utility.question_dialog('Do you really want to open '
                                             + str(len(selected_items))
                                             + ' files?')
            button = dialog.exec()
            if button == QMessageBox.Cancel:
                open = False

        if open:
            for item in selected_items:
                if (item.isDir()):
                    next_path = item.absoluteFilePath()
                    self.update_current_path(next_path)
                elif (item.isFile()):
                    if (item.isExecutable()):
                        QProcess().startDetached(item.absoluteFilePath(),
                                                 [],
                                                 self.current_path)
                    else:
                        QProcess().startDetached('xdg-open',
                                                 [item.absoluteFilePath()],
                                                 self.current_path)
                else:
                    dialog = utility.message_dialog('The type of the selected'
                                                    + ' file can not be'
                                                    + ' detected.',
                                                    QMessageBox.Warning)
                    dialog.exec()
Beispiel #3
0
    def check_external_program(self, command, args, log, validator=None):
        process = QProcess()
        process.start(command, args)
        process.waitForFinished()

        output = process.readAllStandardOutput() + process.readAllStandardError()

        if process.exitCode() == 0:
            validation_ok = True

            if validation_ok:
                log += "<b><font color=\"green\">OK</font></b>"
                return True, log

        log += "<font color=\"red\">FAILED</font>"
        log += "<pre>"
        log += output
        log += "</pre>"
        return False, log
Beispiel #4
0
    def closeEvent(self, event):
        if QMessageBox.question(self, "退出程序", "确定退出吗?") == QMessageBox.No:
            event.ignore()
        else:
            event.accept()
            self.shutdown_aria2.emit()


# - [x]: 在线程Thread1跑界面,再在Thread1中开一个进程跑aria2RPC伺服
# - [ ]: 在线程Thread2跑下载,获取下载状态,传递给界面的progressBar(信号与槽)
# - [ ]: 在Thread1中用按钮控制Thread2的下载(信号与槽)
# >> (It is safe to connect signals and slots across different threads)

if __name__ == "__main__":
    process_aria2 = QProcess()
    program = "aria2c.exe"
    arguments = [
        '--enable-rpc=true', '--allow-overwrite=false',
        '--max-overall-download-limit=1M'
    ]
    process_aria2.start(program, arguments)

    app = QApplication()
    w = MyWidget()

    dt = DownloadThread([w.lineEditorUrl.text()])

    dt.resultReady.connect(w.updateProgress)

    # w.buttonStart.clicked.connect(dt.download)
Beispiel #5
0
def runProcess(command, arguments):
    process = QProcess()
    process.start(command, arguments)
    process.waitForFinished()
    std_output = process.readAllStandardOutput().data().decode('utf-8')
    return std_output.split('\n')
Beispiel #6
0
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        #self.ui = ()
        self.setupUi(self)

        self.p: QProcess = None

        dirname = r"K:\Media Library"

        processing_dirs = getBaseDirs(dirname)

        s: QtCore.QSize = self.treeView.iconSize()
        self.message(f'size = {s}')
        s = QtCore.QSize(16, 16)  # Set icon sizing here
        self.treeView.setIconSize(s)

        style = QApplication.style()
        self.running_icon = style.standardIcon(QStyle.SP_BrowserReload)
        self.done_icon = style.standardIcon(QStyle.SP_DialogApplyButton)
        self.failed_icon = style.standardIcon(QStyle.SP_MessageBoxCritical)
        self.missing_icon = style.standardIcon(
            QStyle.SP_TitleBarContextHelpButton)
        self.added_icon = style.standardIcon(QStyle.SP_ArrowUp)
        self.warning_icon = style.standardIcon(QStyle.SP_MessageBoxWarning)

        self.checksum_sets = []

        for dirname in processing_dirs:
            self.checksum_sets.append(ChecksumSet(dirname))

        self.updateStats()

        self.populateModel()
        self.treeView.setModel(self.model)
        #   self.treeView.setExpandsOnDoubleClick(True)

        #      for x in self.iterItems(self.model.invisibleRootItem()):
        #    y = x.data(role=DisplayRole)
        #     z = x.data(role=UserRole)
        #    self.message(f'y = {y}, z = {z}')
        #    x.setText('hi')
        #         y = x.data(role=QtCore.Qt.UserRole)
        #        self.message(x.text())

        #        self.message('HI' + y.baseDirname)
        #        self.message('HI' + str(y))

        self.start_process()

    #   model.setHorizontalHeaderLabels(['Title', 'Summary'])
    #   rootItem = model.invisibleRootItem()

    #First top-level row and children
    #   item0 = [QStandardItem('Title0'), QStandardItem('Summary0')]

    #    item00 = [QStandardItem('Title00'), QStandardItem('Summary00')]
    #    item01 = [QStandardItem('Title01'), QStandardItem('Summary01')]
    #   rootItem.appendRow(item0)
    #    item0[0].appendRow(item00)
    #    item0[0].appendRow(item01)

    #Second top-level item and its children
    #    item1 = [QStandardItem('Title1'), QStandardItem('Summary1')]
    #    item10 = [QStandardItem('Title10'), QStandardItem('Summary10')]
    #    item11 = [QStandardItem('Title11'), QStandardItem('Summary11')]
    #    item12 = [QStandardItem('Title12'), QStandardItem('Summary12')]
    #    rootItem.appendRow(item1)
    #    item1[0].appendRow(item10)
    #    item1[0].appendRow(item11)
    #    item1[0].appendRow(item12)

    #Children of item11 (third level items)
    #    item110 = [QStandardItem('Title110'), QStandardItem('Summary110')]
    #    item111 = [QStandardItem('Title111'), QStandardItem('Summary111')]
    #    item11[0].appendRow(item110)
    #    item11[0].appendRow(item111)

    def toast_notification(self, title, text):
        AppID = 'zchecksum'
        XML = ToastNotificationManager.get_template_content(
            ToastTemplateType.TOAST_TEXT02)
        print(XML)
        t = XML.get_elements_by_tag_name("text")
        print(t)
        t[0].append_child(XML.create_text_node(title))
        t[1].append_child(XML.create_text_node(text))
        notifier = ToastNotificationManager.create_toast_notifier(AppID)
        notifier.show(ToastNotification(XML))

    def iterItems(self, root):
        if root is not None:
            for row in range(root.rowCount()):
                row_item = root.child(row, 0)
                if row_item.hasChildren():
                    for childIndex in range(row_item.rowCount()):
                        # Take second column from "child"-row
                        child = row_item.child(childIndex, 1)
                        yield child

    def format_size(self, size):
        if size < 0:
            raise Exception('Unknown file size')

        if size < 1024:
            return f'{size} Bytes'
        elif size < 1024 * 1024:
            size_kb = size / 1024
            return f'{size_kb:.1f} KB'
        elif size < 1024 * 1024 * 1024:
            size_mb = size / 1024 / 1024
            return f'{size_mb:.1f} MB'
        else:
            size_gb = size / 1024 / 1024 / 1024
            return f'{size_gb:.1f} GB'

    def populateModel(self):

        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels([
            'Status', 'Directory / Filename', 'File Count', 'Size', 'Checksum',
            'Last Verified'
        ])
        rootItem = self.model.invisibleRootItem()

        for checksum_set in self.checksum_sets:
            last_verified = ''
            status = ''
            if not checksum_set.hasSha512File():
                status = 'New'
            elif checksum_set.has_changes():
                status = "Modified"
                self.toast_notification("Checksum set was modified.",
                                        checksum_set.baseDirname)
            else:
                time_delta = datetime.now(
                ) - checksum_set.sha512File.last_verified
                last_verified = f'{time_delta.days} days ago'
                if time_delta.days > good_days:
                    status = 'Test'
                else:
                    status = 'Good'

            if status == 'Test' or status == 'New' or status == 'Modified':
                item = [
                    QStandardItem(status),
                    QStandardItem(checksum_set.baseDirname),
                    QStandardItem(str(len(checksum_set.filenames))),
                    QStandardItem(''),
                    QStandardItem(''),
                    QStandardItem(last_verified)
                ]
                for filename in checksum_set.filenames:
                    checksum_text = ''
                    file_status = ''
                    if checksum_set.sha512File:
                        checksum = checksum_set.sha512File.findChecksum(
                            filename)
                        if checksum:
                            checksum_text = checksum
                        else:
                            file_status = 'Added'
                    size = Path(checksum_set.baseDirname +
                                filename).stat().st_size
                    size_display = self.format_size(size)
                    #     sz = len(checksum_set.baseDirname) + len(filename)
                    c_item = [
                        QStandardItem(file_status),
                        QStandardItem(filename),
                        QStandardItem(''),
                        QStandardItem(size_display),
                        QStandardItem(checksum_text)
                    ]
                    c_item[1].setData(checksum_set, QtCore.Qt.UserRole)
                    if file_status == 'Added':
                        c_item[0].setIcon(self.added_icon)
                    if filename == 'Thumbs.db':
                        c_item[0].setIcon(self.warning_icon)
                    item[0].appendRow(c_item)
                if checksum_set.hasSha512File():
                    for filename in checksum_set.get_missing_from_dir():
                        checksum_text = checksum_set.sha512File.findChecksum(
                            filename)
                        c_item = [
                            QStandardItem('Missing'),
                            QStandardItem(filename),
                            QStandardItem(''),
                            QStandardItem('n/a'),
                            QStandardItem(checksum_text)
                        ]
                        c_item[1].setData(checksum_set, QtCore.Qt.UserRole)
                        c_item[0].setIcon(self.missing_icon)
                        item[0].appendRow(c_item)
                rootItem.appendRow(item)

    #    self.showIssues()

    #TODO: FIX, NOT WORKING!
    def showIssues(self):
        self.treeView.expandAll()
        root = self.model.invisibleRootItem()
        if root is not None:
            for row in range(root.rowCount()):
                row_item = root.child(row, 0)
                if row_item.hasChildren():
                    for childIndex in range(row_item.rowCount()):
                        # Take second column from "child"-row
                        child = row_item.child(childIndex, 1)

                        filename = child.text()
                        print(f'f = {filename}, {row_item.index()}')
                        if filename == 'Thumbs.db':
                            self.treeView.setExpanded(row_item.index(), True)
                        #   c_item[0].setIcon(self.warning_icon)
                        #   item[0].setExpanded(True)

    #   self.start_process()

    #   header = self.treeWidget.header()
    #  header

    #    header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
    #    header.setStretchLastSection(False)
    #   header.setSectionResizeMode(5, QtWidgets.QHeaderView.Stretch)

    def updateStats(self):
        new_count = 0
        modified_count = 0
        test_count = 0
        good_count = 0

        #    items = []
        for checksum_set in self.checksum_sets:
            if not checksum_set.hasSha512File():
                new_count += 1
            elif checksum_set.has_changes():
                modified_count += 1
            else:
                time_delta = datetime.now(
                ) - checksum_set.sha512File.last_verified
                if time_delta.days > good_days:
                    test_count += 1
                else:
                    good_count += 1

        self.statusBar().showMessage(
            f'Total sets: {len(self.checksum_sets)} sets.   New sets: {new_count}   Modified sets: {modified_count}   Test sets: {test_count}   Good sets: {good_count}'
        )

    def message(self, s):
        #    self.statusBar().showMessage(s)
        self.listWidget.addItem(s)

    def start_process(self):
        root = self.model.invisibleRootItem()

        started_count = 0

        if root is not None:
            for row in range(root.rowCount()):

                if self.p:
                    break

                row_item = root.child(row, 0)
                #  item = self.model.item(row)
                dir = root.child(row, 1)
                set_status = root.child(row, 0)

                #       self.message(dir.text())
                if (set_status.text() == "New" or set_status.text()
                        == 'Test') and row_item.hasChildren():
                    for childIndex in range(row_item.rowCount()):
                        # Take second column from "child"-row
                        #  status = row_item.child(childIndex, 0)

                        #   self.message(status.text())
                        #          if status.text() == 'New':
                        #              self.message(dir.text())

                        status = row_item.child(childIndex, 0)
                        filename = row_item.child(childIndex, 1)
                        #      self.message(filename.text())
                        #   checksum_item = row_item.child(childIndex, 4)

                        if status.text() != "Done":
                            #      parent = filename.parent()
                            #       self.message("parent " + str(parent))

                            self.run_process(dir.text(), filename.text(),
                                             row_item, childIndex)
                            started_count += 1

                            if self.p:
                                break

        self.message(f'start_process done.  Started {started_count}')

        #  yield child

#     for i in range(self.model.rowCount()):
#                 item = self.model.item(i)

#    root = self.treeWidget.invisibleRootItem()
#    child_count = root.childCount()
#    for i in range(child_count):
#        item = ro
# ot.child(i)
#       url = item.text(0) # text at first (0) column
#        item.setText(1, 'result from %s' % url) # update result column (1)

    def run_process(self, dir, filename, set_item, childIndex):
        if self.p is None:  # No process running.
            self.p_item = dict(set_item=set_item, child_index=childIndex)
            self.p = QProcess(
            )  # Keep a reference to the QProcess (e.g. on self) while it's running.

            #    item
            #       self.p.readyReadStandardOutput.connect(self.handle_stdout)
            self.p.readyReadStandardError.connect(self.handle_stderr)
            self.p.stateChanged.connect(self.handle_state)
            self.p.finished.connect(
                self.process_finished)  # Clean up once complete.

            #   filename = r"J:\Media Library\TV\New\Family Guy\Misc\Family Guy S07E11.avi"

            filepath = dir + filename
            self.message("Executing process for file: " + filepath)

            if Path(filepath).stat().st_size > 0:
                args = ["-hashfile", filepath, "SHA512"]
                self.p.start("certutil", args)
            else:
                # CertUtil cannot compute hashes on empty files
                args = ["zero_sha512.py"]
                self.p.start("python", args)

            status = set_item.child(childIndex, 0)

            status.setIcon(self.running_icon)
            set_item.setIcon(self.running_icon)

            if status.text() == '':
                if set_item.text() != 'Test':
                    set_item.child(childIndex, 0).setText('Running Pass 1/3')
                else:
                    set_item.child(childIndex, 0).setText('Running')
            elif status.text() == 'Running Pass 1/3':
                set_item.child(childIndex, 0).setText('Running Pass 2/3')
            elif status.text() == 'Running Pass 2/3':
                set_item.child(childIndex, 0).setText('Running Pass 3/3')

        else:
            self.message("process already running!")

    def handle_stderr(self):
        data = self.p.readAllStandardError()
        stderr = bytes(data).decode("utf8")
        # Extract progress if it is in the data.
        #     progress = simple_percent_parser(stderr)
        #     if progress:
        #         self.progress.setValue(progress)
        self.message(stderr)

    def handle_stdout(self):
        data = self.p.readAllStandardOutput()
        stdout = bytes(data).decode("utf8")
        self.message(stdout)

    def handle_state(self, state):
        states = {
            QProcess.NotRunning: 'Not running',
            QProcess.Starting: 'Starting',
            QProcess.Running: 'Running',
        }
        state_name = states[state]
        self.message(f"State changed: {state_name}")

    def process_finished(self, exitCode, exitStatus):

        row_item = self.p_item['set_item']
        child_index = self.p_item['child_index']
        status_item = row_item.child(child_index, 0)
        filename_item = row_item.child(child_index, 1)

        try:
            checksum_set = filename_item.data(QtCore.Qt.UserRole)

            if checksum_set is None:
                self.toast_notification(
                    "Checksum set not found.",
                    "No checksum set for file " + filename_item.text())
                raise Exception("No checksum set found")

            self.message(
                f'Process finished. exitCode = {exitCode}, exitStatus = {exitStatus}, baseDirname = {checksum_set.baseDirname}'
            )

            data = self.p.readAllStandardOutput()

            #       stdout = bytes(data)
            #      self.message("normal stdout: " + stdout)
            #  .decode('iso-8859-1').encode('utf8')
            #    stdout = bytes(data).decode("iso-8859-1")
            #try:
            stdout = bytes(data).decode('utf8', 'replace')
            #  except:
            #      stdout = bytes(data).decode('iso-8859-1')

            #   self.message("row_item" + row_item)
            self.message("stdout: " + stdout)

            lines = stdout.splitlines()

            if exitCode != 0 or len(lines) != 3:
                msg = f'Compute SHA512 failed.  stdout: ({stdout})'
                error_message = ''
                if len(lines) > 1 and lines[1].startswith("CertUtil: "):
                    error_message = lines[1][10:]

            #   msg = f'Error: Compute SHA512 failed for file {filename}.  stdout: ({cp.stdout}) stderr: ({cp.stderr})'
        #       print(msg)
                self.toast_notification(
                    'Failed to compute checksum. ' + error_message,
                    filename_item.text())
                raise Exception(msg)

            new_checksum = lines[1].replace(" ", "")

            checksum_item = row_item.child(child_index, 4)

            old_checksum = checksum_item.text()

            if old_checksum == "":
                checksum_item.setText(new_checksum)
            elif new_checksum != old_checksum:
                msg = f'Checksums do not match.'
                self.toast_notification('Checksums mismatch',
                                        filename_item.text())
                raise Exception(msg)

            if status_item.text() == "Running Pass 3/3" or status_item.text(
            ) == 'Running':
                status_item.setText('Done')
                status_item.setIcon(self.done_icon)

        #   checksum = QStandardItem()
        #   row_item.setChild(0, 4, checksum)
        # my_item.setText()

        #  my_item.setText(0, "Done")
        #  self.message("my_item: " + my_item.text(1))

    #     if self.all_files_done_checksum(row_item.parent()):
    #        self.create_sha_file(my_item.parent())

            if self.all_files_done_checksum(row_item):
                row_item.setIcon(self.done_icon)
                row_item.setText("Done")
                if checksum_set.hasSha512File():
                    self.message(
                        f'Updating {checksum_set.baseDirname} checksum file modified date'
                    )
                    checksum_set.update_modified()
                else:
                    self.create_sha_file(row_item)
        except Exception as e:
            status_item.setText("Failed")
            status_item.setIcon(self.failed_icon)
            row_item.setText("Failed")
            row_item.setIcon(self.failed_icon)
            self.message("Error: " + str(e))
        finally:
            self.p = None
            self.start_process()

    def all_files_done_checksum(self, set_item):
        for childIndex in range(set_item.rowCount()):
            status_item = set_item.child(childIndex, 0)
            checksum_item = set_item.child(childIndex, 4)
            filename_item = set_item.child(childIndex, 1)
            self.message(filename_item.text())

            if status_item.text() != 'Done' or checksum_item.text() == '':
                return False

        return True

    def create_sha_file(self, set_item):
        self.message("create_sha_file!!")

        # index = set_item.index()

        #  self.message(f'index = {index}')
        #  dirname = self.model.item(index, 1)

        #   dirname = set_item.data(1)

        dir = self.model.invisibleRootItem().child(set_item.row(), 1)

        dirname = dir.text()
        self.message(
            f'create_sha_file2, dir = {dir.text()}, row = {set_item.row()}, set_item.columnCount = {set_item.columnCount()}'
        )

        shaFile = Sha512(dirname)

        for childIndex in range(set_item.rowCount()):
            checksum_item = set_item.child(childIndex, 4)

            filename_item = set_item.child(childIndex, 1)
            self.message(filename_item.text())

            shaFile.addFileAndChecksum(filename_item.text(),
                                       checksum_item.text())

        shaFile.writeFile()
Beispiel #7
0
 def __init__(self, parent=None):
     super(MainWindow, self).__init__()
     self.statusBar().showMessage("Move Dial to Deform Microphone Voice !.")
     self.setWindowTitle(__doc__)
     self.setMinimumSize(240, 240)
     self.setMaximumSize(480, 480)
     self.resize(self.minimumSize())
     self.setWindowIcon(QIcon.fromTheme("audio-input-microphone"))
     self.tray = QSystemTrayIcon(self)
     self.center()
     QShortcut("Ctrl+q", self, activated=lambda: self.close())
     self.menuBar().addMenu("&File").addAction("Quit", lambda: exit())
     self.menuBar().addMenu("Sound").addAction(
         "STOP !", lambda: call('killall rec', shell=True))
     windowMenu = self.menuBar().addMenu("&Window")
     windowMenu.addAction("Hide", lambda: self.hide())
     windowMenu.addAction("Minimize", lambda: self.showMinimized())
     windowMenu.addAction("Maximize", lambda: self.showMaximized())
     windowMenu.addAction("Restore", lambda: self.showNormal())
     windowMenu.addAction("FullScreen", lambda: self.showFullScreen())
     windowMenu.addAction("Center", lambda: self.center())
     windowMenu.addAction("Top-Left", lambda: self.move(0, 0))
     windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position())
     # widgets
     group0 = QGroupBox("Voice Deformation")
     self.setCentralWidget(group0)
     self.process = QProcess(self)
     self.process.error.connect(
         lambda: self.statusBar().showMessage("Info: Process Killed", 5000))
     self.control = QDial()
     self.control.setRange(-10, 20)
     self.control.setSingleStep(5)
     self.control.setValue(0)
     self.control.setCursor(QCursor(Qt.OpenHandCursor))
     self.control.sliderPressed.connect(
         lambda: self.control.setCursor(QCursor(Qt.ClosedHandCursor)))
     self.control.sliderReleased.connect(
         lambda: self.control.setCursor(QCursor(Qt.OpenHandCursor)))
     self.control.valueChanged.connect(
         lambda: self.control.setToolTip(f"<b>{self.control.value()}"))
     self.control.valueChanged.connect(lambda: self.statusBar().showMessage(
         f"Voice deformation: {self.control.value()}", 5000))
     self.control.valueChanged.connect(self.run)
     self.control.valueChanged.connect(lambda: self.process.kill())
     # Graphic effect
     self.glow = QGraphicsDropShadowEffect(self)
     self.glow.setOffset(0)
     self.glow.setBlurRadius(99)
     self.glow.setColor(QColor(99, 255, 255))
     self.control.setGraphicsEffect(self.glow)
     self.glow.setEnabled(False)
     # Timer to start
     self.slider_timer = QTimer(self)
     self.slider_timer.setSingleShot(True)
     self.slider_timer.timeout.connect(self.on_slider_timer_timeout)
     # an icon and set focus
     QLabel(self.control).setPixmap(
         QIcon.fromTheme("audio-input-microphone").pixmap(32))
     self.control.setFocus()
     QVBoxLayout(group0).addWidget(self.control)
     self.menu = QMenu(__doc__)
     self.menu.addAction(__doc__).setDisabled(True)
     self.menu.setIcon(self.windowIcon())
     self.menu.addSeparator()
     self.menu.addAction(
         "Show / Hide", lambda: self.hide()
         if self.isVisible() else self.showNormal())
     self.menu.addAction("STOP !", lambda: call('killall rec', shell=True))
     self.menu.addSeparator()
     self.menu.addAction("Quit", lambda: exit())
     self.tray.setContextMenu(self.menu)
     self.make_trayicon()
Beispiel #8
0
class MainWindow(QMainWindow):
    """Voice Changer main window."""
    def __init__(self, parent=None):
        super(MainWindow, self).__init__()
        self.statusBar().showMessage("Move Dial to Deform Microphone Voice !.")
        self.setWindowTitle(__doc__)
        self.setMinimumSize(240, 240)
        self.setMaximumSize(480, 480)
        self.resize(self.minimumSize())
        self.setWindowIcon(QIcon.fromTheme("audio-input-microphone"))
        self.tray = QSystemTrayIcon(self)
        self.center()
        QShortcut("Ctrl+q", self, activated=lambda: self.close())
        self.menuBar().addMenu("&File").addAction("Quit", lambda: exit())
        self.menuBar().addMenu("Sound").addAction(
            "STOP !", lambda: call('killall rec', shell=True))
        windowMenu = self.menuBar().addMenu("&Window")
        windowMenu.addAction("Hide", lambda: self.hide())
        windowMenu.addAction("Minimize", lambda: self.showMinimized())
        windowMenu.addAction("Maximize", lambda: self.showMaximized())
        windowMenu.addAction("Restore", lambda: self.showNormal())
        windowMenu.addAction("FullScreen", lambda: self.showFullScreen())
        windowMenu.addAction("Center", lambda: self.center())
        windowMenu.addAction("Top-Left", lambda: self.move(0, 0))
        windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position())
        # widgets
        group0 = QGroupBox("Voice Deformation")
        self.setCentralWidget(group0)
        self.process = QProcess(self)
        self.process.error.connect(
            lambda: self.statusBar().showMessage("Info: Process Killed", 5000))
        self.control = QDial()
        self.control.setRange(-10, 20)
        self.control.setSingleStep(5)
        self.control.setValue(0)
        self.control.setCursor(QCursor(Qt.OpenHandCursor))
        self.control.sliderPressed.connect(
            lambda: self.control.setCursor(QCursor(Qt.ClosedHandCursor)))
        self.control.sliderReleased.connect(
            lambda: self.control.setCursor(QCursor(Qt.OpenHandCursor)))
        self.control.valueChanged.connect(
            lambda: self.control.setToolTip(f"<b>{self.control.value()}"))
        self.control.valueChanged.connect(lambda: self.statusBar().showMessage(
            f"Voice deformation: {self.control.value()}", 5000))
        self.control.valueChanged.connect(self.run)
        self.control.valueChanged.connect(lambda: self.process.kill())
        # Graphic effect
        self.glow = QGraphicsDropShadowEffect(self)
        self.glow.setOffset(0)
        self.glow.setBlurRadius(99)
        self.glow.setColor(QColor(99, 255, 255))
        self.control.setGraphicsEffect(self.glow)
        self.glow.setEnabled(False)
        # Timer to start
        self.slider_timer = QTimer(self)
        self.slider_timer.setSingleShot(True)
        self.slider_timer.timeout.connect(self.on_slider_timer_timeout)
        # an icon and set focus
        QLabel(self.control).setPixmap(
            QIcon.fromTheme("audio-input-microphone").pixmap(32))
        self.control.setFocus()
        QVBoxLayout(group0).addWidget(self.control)
        self.menu = QMenu(__doc__)
        self.menu.addAction(__doc__).setDisabled(True)
        self.menu.setIcon(self.windowIcon())
        self.menu.addSeparator()
        self.menu.addAction(
            "Show / Hide", lambda: self.hide()
            if self.isVisible() else self.showNormal())
        self.menu.addAction("STOP !", lambda: call('killall rec', shell=True))
        self.menu.addSeparator()
        self.menu.addAction("Quit", lambda: exit())
        self.tray.setContextMenu(self.menu)
        self.make_trayicon()

    def run(self):
        """Run/Stop the QTimer."""
        if self.slider_timer.isActive():
            self.slider_timer.stop()
        self.glow.setEnabled(True)
        call('killall rec ; killall play', shell=True)
        self.slider_timer.start(3000)

    def on_slider_timer_timeout(self):
        """Run subprocess to deform voice."""
        self.glow.setEnabled(False)
        value = int(self.control.value()) * 100
        command = f'play -q -V0 "|rec -q -V0 -n -d -R riaa bend pitch {value} "'
        print(f"Voice Deformation Value: {value}")
        print(f"Voice Deformation Command: {command}")
        self.process.start(command)
        if self.isVisible():
            self.statusBar().showMessage("Minimizing to System TrayIcon", 3000)
            print("Minimizing Main Window to System TrayIcon now...")
            sleep(3)
            self.hide()

    def center(self):
        """Center Window on the Current Screen,with Multi-Monitor support."""
        window_geometry = self.frameGeometry()
        mousepointer_position = QApplication.desktop().cursor().pos()
        screen = QApplication.desktop().screenNumber(mousepointer_position)
        centerPoint = QApplication.desktop().screenGeometry(screen).center()
        window_geometry.moveCenter(centerPoint)
        self.move(window_geometry.topLeft())

    def move_to_mouse_position(self):
        """Center the Window on the Current Mouse position."""
        window_geometry = self.frameGeometry()
        window_geometry.moveCenter(QApplication.desktop().cursor().pos())
        self.move(window_geometry.topLeft())

    def make_trayicon(self):
        """Make a Tray Icon."""
        if self.windowIcon() and __doc__:
            self.tray.setIcon(self.windowIcon())
            self.tray.setToolTip(__doc__)
            self.tray.activated.connect(
                lambda: self.hide() if self.isVisible() else self.showNormal())
            return self.tray.show()
Beispiel #9
0
    def __init__(self, parent=None) -> None:
        super().__init__(parent)

        self.verticalLayout = QVBoxLayout(self)

        self.compileButton = QPushButton('Compile', self)
        self.compileButton.setMinimumSize(QSize(200, 50))
        self.verticalLayout.addWidget(self.compileButton, 0, Qt.AlignHCenter)

        self.tidyButton = QPushButton('Tidy', self)
        self.verticalLayout.addWidget(self.tidyButton, 0, Qt.AlignHCenter)

        self.splitter = QSplitter(self)
        self.splitter.setOrientation(Qt.Vertical)

        self.widget = QWidget(self.splitter)
        self.widget.setObjectName(u"widget")
        self.verticalLayout2 = QVBoxLayout(self.widget)
        self.stdoutLabel = QLabel(self.widget)
        self.stdoutLabel.setText('stdout:')

        self.verticalLayout2.addWidget(self.stdoutLabel)

        self.stdoutText = QTextEdit(self.widget)
        self.stdoutText.setEnabled(False)
        self.stdoutText.setReadOnly(True)
        self.stdoutText.setPlainText("Output will appear here")

        self.verticalLayout2.addWidget(self.stdoutText)

        self.splitter.addWidget(self.widget)

        self.widget1 = QWidget(self.splitter)

        self.verticalLayout3 = QVBoxLayout(self.widget1)
        self.stderrLabel = QLabel(self.widget1)
        self.stderrLabel.setText('stderr:')

        self.verticalLayout3.addWidget(self.stderrLabel)

        self.stderrText = QTextEdit(self.widget1)
        self.stderrText.setEnabled(False)
        self.stderrText.setReadOnly(True)
        self.stderrText.setPlainText('Errors will appear here')

        self.verticalLayout3.addWidget(self.stderrText)

        self.splitter.addWidget(self.widget1)

        self.verticalLayout.addWidget(self.splitter)

        # Logic

        # Use QProcess to start a program and get its outputs https://stackoverflow.com/a/22110924
        self.process = QProcess(self)

        self.process.readyReadStandardOutput.connect(self.readStdout)
        self.process.readyReadStandardError.connect(self.readStderr)
        self.process.started.connect(self.processStarted)
        self.process.finished.connect(self.processFinished)
        self.process.errorOccurred.connect(self.errorOccurred)
        self.compileButton.clicked.connect(self.doCompile)
        self.tidyButton.clicked.connect(self.doTidy)
Beispiel #10
0
class BuilderWidget(QWidget):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)

        self.verticalLayout = QVBoxLayout(self)

        self.compileButton = QPushButton('Compile', self)
        self.compileButton.setMinimumSize(QSize(200, 50))
        self.verticalLayout.addWidget(self.compileButton, 0, Qt.AlignHCenter)

        self.tidyButton = QPushButton('Tidy', self)
        self.verticalLayout.addWidget(self.tidyButton, 0, Qt.AlignHCenter)

        self.splitter = QSplitter(self)
        self.splitter.setOrientation(Qt.Vertical)

        self.widget = QWidget(self.splitter)
        self.widget.setObjectName(u"widget")
        self.verticalLayout2 = QVBoxLayout(self.widget)
        self.stdoutLabel = QLabel(self.widget)
        self.stdoutLabel.setText('stdout:')

        self.verticalLayout2.addWidget(self.stdoutLabel)

        self.stdoutText = QTextEdit(self.widget)
        self.stdoutText.setEnabled(False)
        self.stdoutText.setReadOnly(True)
        self.stdoutText.setPlainText("Output will appear here")

        self.verticalLayout2.addWidget(self.stdoutText)

        self.splitter.addWidget(self.widget)

        self.widget1 = QWidget(self.splitter)

        self.verticalLayout3 = QVBoxLayout(self.widget1)
        self.stderrLabel = QLabel(self.widget1)
        self.stderrLabel.setText('stderr:')

        self.verticalLayout3.addWidget(self.stderrLabel)

        self.stderrText = QTextEdit(self.widget1)
        self.stderrText.setEnabled(False)
        self.stderrText.setReadOnly(True)
        self.stderrText.setPlainText('Errors will appear here')

        self.verticalLayout3.addWidget(self.stderrText)

        self.splitter.addWidget(self.widget1)

        self.verticalLayout.addWidget(self.splitter)

        # Logic

        # Use QProcess to start a program and get its outputs https://stackoverflow.com/a/22110924
        self.process = QProcess(self)

        self.process.readyReadStandardOutput.connect(self.readStdout)
        self.process.readyReadStandardError.connect(self.readStderr)
        self.process.started.connect(self.processStarted)
        self.process.finished.connect(self.processFinished)
        self.process.errorOccurred.connect(self.errorOccurred)
        self.compileButton.clicked.connect(self.doCompile)
        self.tidyButton.clicked.connect(self.doTidy)

    def doCompile(self):
        self.cleanupUI()
        self.process.setWorkingDirectory(settings.get_repo_location())
        self.process.startCommand(settings.get_build_command())

    def doTidy(self):
        self.cleanupUI()
        self.process.setWorkingDirectory(settings.get_repo_location())
        self.process.startCommand(settings.get_tidy_command())

    def cleanupUI(self):
        self.stdoutText.setEnabled(True)
        self.stderrText.setEnabled(True)
        self.stdoutText.setPlainText('')
        self.stderrText.setPlainText('')

    def readStdout(self):
        lines = self.process.readAllStandardOutput().data().decode(
        )[:-1].split('\n')
        for line in lines:
            if line == 'tmc.gba: FAILED':
                line = 'tmc.gba: <b style="color:red">FAILED</b>'
            elif line == 'tmc.gba: OK':
                line = 'tmc.gba: <b style="color:lime">OK</b>'
            self.stdoutText.append(line)

    def readStderr(self):
        lines = self.process.readAllStandardError().data().decode()[:-1].split(
            '\n')
        for line in lines:
            if 'error' in line.lower():
                line = f'<span style="color:red">{line}</span>'
            elif 'warning' in line.lower():
                line = f'<span style="color:orange">{line}</span>'

            self.stderrText.append(line)

    def processStarted(self):
        self.compileButton.setEnabled(False)
        self.tidyButton.setEnabled(False)

    def processFinished(self):
        self.compileButton.setEnabled(True)
        self.tidyButton.setEnabled(True)

    def errorOccurred(self):
        self.stderrText.insertPlainText(self.process.errorString())
Beispiel #11
0
def parse_asn1(*files, **options):
    ''' Call the ASN.1 parser on a number of files, and return the module
        containing the AST
        This function uses QProcess to launch the ASN.1 compiler because
        the subprocess module from Python has issues on the Windows platform
    '''
    if '-g' in sys.argv:
        os.environ["PROJECT_CACHE"] = './debug'

    # use basic caching to avoid re-parsing when loading the model
    project_cache = os.getenv("PROJECT_CACHE")
    if project_cache is not None and not os.path.isdir(project_cache):
        try:
            print(f"[INFO] Creating cache folder {project_cache}")
            os.makedirs(project_cache)
        except OSError:
            raise TypeError(
                f'''The configured cache folder "{project_cache} " \
                is not there and could not be created\n''')
    # make sure the same files are not parsed more than once if not modified
    filehash = hashlib.md5()
    file_list = sorted(list(*files))
    try:
        for each in file_list:
            filehash.update(open(each).read().encode('utf-8'))
            # also hash the file path: it is used in the AST, so it is
            # not enough to hash the content of the ASN.1 files, as two sets
            # of input files may have the same hash
            filehash.update(each.encode('utf-8'))
    except IOError as err:
        raise TypeError(str(err))
    new_hash = filehash.hexdigest()

    # names of the files that will be generated by asn1scc and then parsed
    out_py_name = new_hash + ".py"
    out_html_name = new_hash + ".html"

    if new_hash in AST.keys():
        return AST[new_hash]
    elif project_cache is not None:
        outdir = project_cache
    elif project_cache is None:
        outdir = tempfile.mkdtemp()

    # to allow the import
    sys.path.append(outdir)

    ast_version = options.get('ast_version', ASN1.UniqueEnumeratedNames)
    rename_policy = options.get('rename_policy', ASN1.NoRename)
    flags = options.get('flags', [ASN1.AstOnly])
    pprint = options.get('pretty_print', False)
    extraflags = options.get('extraflags', [])
    assert isinstance(ast_version, ASN1)
    assert isinstance(rename_policy, ASN1)
    assert isinstance(flags, list)
    path_to_asn1scc = spawn.find_executable('asn1scc')

    if not path_to_asn1scc:
        raise TypeError('ASN.1 Compiler (asn1scc) not found in path')
    binary = path_to_asn1scc
    asn1scc_root = os.path.abspath(os.path.dirname(binary))

    if os.name == 'nt':
        # On windows, remove the drive letter, workaround to ASN1SCC bug
        outdir = outdir[2:]
        asn1scc_root = asn1scc_root[2:]

    # The two possible files that can be generated with complete path:
    py_filepath = outdir + os.sep + out_py_name
    html_filepath = outdir + os.sep + out_html_name

    # call the ASN.1 compiler only if there is no existing cached file
    if project_cache is None or not os.path.exists(py_filepath):
        stg = asn1scc_root + os.sep + 'python.stg'

        if pprint:
            # Generate an html file with pretty-printed ASN.1 types
            stg_qrc = QFile(':misc/pretty_print_asn1.stg')
            stg_qrc.open(QIODevice.ReadOnly)
            content = stg_qrc.readAll()
            stgfile = outdir + os.sep + 'pretty_print_asn1.stg'
            with open(stgfile, 'wb') as tmpfile:
                tmpfile.write(content.data())
            html = ['-customIcdUper', stgfile + '::' + html_filepath]
        else:
            html = []
        args = [
            '-customStgAstVersion',
            str(ast_version.value), '--field-prefix', 'AUTO', '-customStg',
            stg + '::' + py_filepath, '-renamePolicy',
            str(rename_policy.value)
        ] + html + extraflags + file_list
        asn1scc = QProcess()
        LOG.debug(os.getcwd())
        LOG.debug(args)
        LOG.debug(binary + ' ' + ' '.join(args))
        LOG.debug(f"Python AST: {py_filepath}")
        asn1scc.start(binary, args)

        _ = waitfor_qprocess(asn1scc, "ASN.1 Compiler")

    ast = importlib.import_module(new_hash)
    AST[new_hash] = ast
    if pprint:
        # add the path to the optionally-generated pretty-printed HTML file
        ast.html = html_filepath
    return ast
Beispiel #12
0
def asn2dataModel(files, outdir=None, db=None):
    ''' Call asn2dataModel, including the Makefile.python and return
    the imported module "name_of_dataview_asn.py"
    From this module it is possible to create native Asn1scc instances of
    ASN.1 data types, and to access to DV.py, which contains constants
    such as the _PRESENT fields for choice selectors.
    In addition the SqlAlchemy interface is also imported
    give db a name to create the database
    if outdir is none, a temporary folder will be used
    '''
    assert len(files) > 0

    # 1) Create a temporary directory for the output
    if '-g' in sys.argv:
        # In debug mode, don't hide the files in /tmp
        os.makedirs('./debug', exist_ok=True)
        tempdir = './debug/'
    elif outdir is None:
        tempdir = tempfile.mkdtemp()
    else:
        os.makedirs(outdir, exist_ok=True)
        tempdir = outdir
    sys.path.insert(0, tempdir)
    # Use a unique name for the asn1 concatenated module
    # concat_prefix = str(uuid.uuid4()).replace('-', '_')
    # Update MP 19/01/2022 - why use a unique name while
    # we are already in a random temp folder?
    concat_prefix = 'og_dataview'
    concat_path = os.path.join(tempdir, concat_prefix)

    concat_file = concat_path + '.asn'
    if os.path.exists(concat_file):
        concat_timestamp = os.path.getctime(concat_file)
    else:
        concat_timestamp = 0

    # 2) Concat all input files to the output directory
    #    if any of the files is more recent that the
    #    existing concatenated file
    cat_bin = spawn.find_executable('cat')
    args = files  # list
    timestamps = []

    for each in args:
        timestamps.append(os.path.getmtime(each))
    if any(ts > concat_timestamp for ts in timestamps):
        cat = QProcess()
        LOG.debug(os.getcwd())
        LOG.debug(cat_bin + ' ' + ' '.join(args))
        cat.start(cat_bin, args)
        merged = waitfor_qprocess(cat, 'Merge dataviews')
        with open(concat_path + '.asn', 'wt') as merged_file:
            merged_file.write(merged.data().decode('utf-8'))

        # 3) Run asn2dataModel for Python
        asn2dm_bin = spawn.find_executable('asn2dataModel')
        args = ['-toPython', '-o', tempdir, concat_path + '.asn']
        asn2dm = QProcess()
        LOG.debug(os.getcwd())
        LOG.debug(asn2dm_bin + ' ' + ' '.join(args))
        asn2dm.start(asn2dm_bin, args)
        waitfor_qprocess(asn2dm, 'DMT tool "asn2dataModel"')

        # 4) call make -f Makefile.python to build the .so
        make_bin = spawn.find_executable('make')
        args = ['-f', 'Makefile.python']
        make = QProcess()
        make.setWorkingDirectory(tempdir)
        LOG.debug(os.getcwd())
        LOG.debug(make_bin + ' ' + ' '.join(args))
        make.start(make_bin, args)
        waitfor_qprocess(make, 'make -f Makefile.python')

        # 5) Run asn2dataModel for the SQL Alchemy module
        args = ['-toSqlalchemy', '-o', tempdir, concat_path + '.asn']
        asn2dm = QProcess()
        LOG.debug(os.getcwd())
        LOG.debug(asn2dm_bin + ' ' + ' '.join(args))
        asn2dm.start(asn2dm_bin, args)
        waitfor_qprocess(asn2dm, 'DMT tool "asn2dataModel"')
    else:
        LOG.info("Reusing DMT outputs from previous run")

    if concat_prefix in ASN2DM.keys():
        # Re-import module if it was already loaded
        asn1mod = ASN2DM[concat_prefix]
        dbmod = asn1mod.db_model
        importlib.reload(asn1mod)
        importlib.reload(asn1mod.DV)
        importlib.reload(dbmod)
        asn1mod.db_model = dbmod
        import Stubs
        importlib.reload(Stubs)
    else:
        asn1mod = importlib.import_module(concat_prefix + '_asn')
        # force reload of modules in case of multiple calls
        importlib.reload(asn1mod.DV)
        import Stubs
        importlib.reload(Stubs)
        # Add the SQL Alchemy module interface
        import db_model
        asn1mod.db_model = db_model
        ASN2DM[concat_prefix] = asn1mod

    # 6) Create the database is "db" is set
    if db is not None:
        # db should be e.g. "sqlite:///file.sqlite"
        from sqlalchemy import create_engine
        from db_model import Base
        engine = create_engine(db, echo=False)
        Base.metadata.create_all(engine)
    sys.path.pop(0)
    return asn1mod