示例#1
0
文件: TransCodaApp.py 项目: ag-sd/py
 def settings_changed(self, setting, _):
     valid_keys = {SettingsKeys.encoder_path}
     if setting in valid_keys:
         self.encoder.setText(TransCodaSettings.get_encoder_name())
     self.tool_bar.set_encode_state(file_count=self.main_panel.row_count(),
                                    encoder_name=TransCodaSettings.get_encoder_name(),
                                    output_dir=TransCodaSettings.get_output_dir())
示例#2
0
文件: File.py 项目: ag-sd/py
 def __init__(self, file, url=None):
     self.file = file
     self.file_name = os.path.split(file)[1]
     self.url = url
     mime_type = _mime_database.mimeTypeForFile(file)
     os_info = os.stat(file)
     self.file_size = os_info.st_size
     self.access_time = os_info.st_atime
     self.modify_time = os_info.st_mtime
     self.create_time = os_info.st_ctime
     self.mime_type_name = mime_type.name()
     self.mime_type_icon_name = mime_type.iconName()
     self.status = EncoderStatus.READING_METADATA
     self.output_file_dir = TransCodaSettings.get_output_dir()
     self.encoder = TransCodaSettings.get_encoder_name()
     self.encoder_props = TransCodaSettings.get_encoder(
     ) if self.encoder is not None else None
     self.output_file = ""
     self.update_output_file()
     self.history_result = None
     self.encode_start_time = None
     self.encode_end_time = None
     self.encode_output_size = None
     self.encode_command = None
     self.encode_percent = None
     self.encode_messages = None
     self.encode_cpu_time = None
     self.encode_compression_ratio = None
     self.meta_data = {}
示例#3
0
文件: File.py 项目: ag-sd/py
 def add_column(self, column):
     self.beginInsertColumns(QModelIndex(), len(self.columnHeaders),
                             len(self.columnHeaders))
     self.columnHeaders.append(column)
     self.endInsertColumns()
     TransCodaSettings.save_columns(self.columnHeaders)
     return len(self.columnHeaders) - 1
示例#4
0
    def _check_file(self):
        if not os.path.exists(self.file.file):
            raise TranscodaError(
                "Input File could not be found on the file system")

        # Overwrite if exists only
        if os.path.exists(
                self.file.output_file
        ) and not TransCodaSettings.get_overwrite_if_exists():
            raise TranscodaError(
                f"Output file {self.file.output_file} already exists!")

        # Ensure path exists
        if self.file.encoder_props["extension"] == "":
            file_path = self.file.output_file
        else:
            file_path, _ = os.path.split(self.file.output_file)
        os.makedirs(file_path, exist_ok=True)

        # Check History
        if self.file.history_result is not None and TransCodaSettings.is_history_enforced(
        ):
            raise TranscodaError(
                f"{self.file.file} has been previously processed. Skipping this file.\n"
                f"Execution Details are: {self.file.history_result}")
示例#5
0
文件: TransCodaApp.py 项目: ag-sd/py
 def jobs_complete_event(self, all_results, time_taken):
     self.progressbar.setValue(self.progressbar.maximum())
     self.executor = None
     self.statusBar().showMessage(f"Processed {len(all_results)} files in {time_taken} seconds", msecs=400)
     self.set_window_title()
     self.tool_bar.encoding_finished(file_count=self.main_panel.row_count(),
                                     encoder_name=TransCodaSettings.get_encoder_name(),
                                     output_dir=TransCodaSettings.get_output_dir())
     self.reset_timer()
示例#6
0
    def do_work(self):
        self.file.encode_start_time = datetime.datetime.now()
        encoder = self.file.encoder_props
        try:
            self._check_file()
        except Exception as exception:
            self.emit_exception(exception)
            return

        # Start encoding
        try:
            if not self.file.is_supported():
                copy_extensions = TransCodaSettings.get_copy_extensions()
                _, extension = os.path.splitext(self.file.output_file)
                if extension.startswith("."):
                    extension = extension[1:]
                if extension.lower() in copy_extensions:
                    executable = "copy"
                else:
                    self.file.status = EncoderStatus.SKIPPED
                    self.signals.result.emit([self.file])
                    return
            else:
                executable = encoder["executable"]
                self.file.encode_command = encoder["command"]
                if executable not in ProcessRunners.runners_registry:
                    raise TranscodaError(
                        f"Unable to find a process handler for executable {executable}"
                    )

            process_runner = ProcessRunners.runners_registry[executable]
            runner = process_runner(
                input_file=self.file.file,
                input_url=self.file.url,
                output_file=self.file.output_file,
                base_command=self.file.encode_command,
                delete_metadata=TransCodaSettings.get_delete_metadata())
            runner.status_event.connect(self.status_event)
            runner.message_event.connect(self.log_message)
            runner.run()
            output_stat = os.stat(self.file.output_file)
            if TransCodaSettings.get_preserve_timestamps():
                os.utime(self.file.output_file,
                         (self.file.access_time, self.file.modify_time))
            self.file.encode_end_time = datetime.datetime.now()
            self.file.encode_cpu_time = (
                self.file.encode_end_time -
                self.file.encode_start_time).total_seconds()
            self.file.encode_compression_ratio = 100 - (
                output_stat.st_size / (self.file.file_size + 1)) * 100
            self.file.status = EncoderStatus.SUCCESS
            self.file.encode_output_size = output_stat.st_size
            self.file.encode_percent = 100
            self.signals.result.emit([self.file])
        except Exception as exception:
            self.emit_exception(exception)
示例#7
0
文件: File.py 项目: ag-sd/py
 def remove_column(self, column):
     del_index = -1
     for index, col in enumerate(self.columnHeaders):
         if col == column:
             del_index = index
             break
     if del_index >= 0:
         self.beginRemoveColumns(QModelIndex(), del_index, del_index)
         del (self.columnHeaders[del_index])
         self.endRemoveColumns()
         TransCodaSettings.save_columns(self.columnHeaders)
示例#8
0
文件: TransCodaApp.py 项目: ag-sd/py
 def files_changed_event(self, is_added, files):
     if is_added:
         self.statusBar().showMessage("Scanning files please wait...")
         scanner = CommonUtils.FileScanner(files, recurse=True, is_qfiles=True)
         self.statusBar().showMessage(f"Loading files into {TransCoda.__APP_NAME__}")
         # Add files first
         total_added = self.main_panel.add_files(scanner.files)
         # Fetch and enrich with metadata
         batches = []
         for batch in CommonUtils.batch(list(scanner.files), batch_size=20):
             retriever = FileMetaDataExtractor(batch, batch_size=len(batch))
             retriever.signals.result.connect(self.result_received_event)
             batches.append(retriever)
         # UX
         self.begin_tasks(batches, f"Fetching meta-data for {total_added} files", total_added)
     self.tool_bar.set_encode_state(file_count=self.main_panel.row_count(),
                                    encoder_name=TransCodaSettings.get_encoder_name(),
                                    output_dir=TransCodaSettings.get_output_dir())
示例#9
0
文件: TransCodaApp.py 项目: ag-sd/py
 def begin_tasks(self, tasks, status_message, total_size, threads=TransCodaSettings.get_max_threads()):
     TransCoda.logger.info(status_message)
     self.progressbar.setVisible(True)
     self.progressbar.setValue(0)
     self.progressbar.setMaximum(total_size)
     self.executor = CommonUtils.CommandExecutionFactory(tasks,
                                                         logger=TransCoda.logger,
                                                         max_threads=threads)
     self.executor.finish_event.connect(self.jobs_complete_event)
     self.statusBar().showMessage(status_message)
     self.executor.start()
示例#10
0
 def _get_icon(self, ico_name, system_fallback=True):
     file_name = f"{ico_name}.svg"
     theme_location = os.path.join(self.resource_dir, file_name)
     default_location = os.path.join(self.__DEFAULT_PATH__, file_name)
     use_system_theme = TransCodaSettings.use_system_theme() and system_fallback
     if not use_system_theme:
         if os.path.exists(theme_location):
             return QIcon(theme_location)
         elif os.path.exists(default_location):
             return QIcon(default_location)
     #     Always fallback to system theme
     return QIcon.fromTheme(ico_name)
示例#11
0
文件: TransCodaApp.py 项目: ag-sd/py
    def init_ui(self):
        encoder_name = TransCodaSettings.get_encoder_name()
        self.main_panel.set_items(TransCodaSettings.get_encode_list())
        self.main_panel.files_changed_event.connect(self.files_changed_event)
        self.main_panel.menu_item_event.connect(self.action_event)
        self.tool_bar.set_encode_state(file_count=self.main_panel.row_count(),
                                       encoder_name=encoder_name,
                                       output_dir=TransCodaSettings.get_output_dir())
        self.tool_bar.button_pressed.connect(self.action_event)
        self.addToolBar(QtCore.Qt.LeftToolBarArea, self.tool_bar)
        self.setCentralWidget(self.main_panel)
        self.statusBar().addPermanentWidget(QVLine())
        if encoder_name:
            self.encoder.setText(TransCodaSettings.get_encoder_name())
        else:
            self.encoder.setText("No encoder selected.")
        self.terminal_btn.setIcon(TransCoda.theme.ico_terminal)
        self.terminal_btn.setFlat(True)
        self.terminal_btn.setToolTip("Show Encoder Logs")
        self.terminal_btn.clicked.connect(self.show_encode_logs)
        self.statusBar().addPermanentWidget(self.encoder, 0)
        self.statusBar().addPermanentWidget(QVLine())
        self.statusBar().addPermanentWidget(self.progressbar, 0)
        self.statusBar().addPermanentWidget(self.terminal_btn, 0)

        self.setMinimumSize(800, 600)
        self.setWindowTitle(TransCoda.__APP_NAME__)
        self.setWindowIcon(TransCoda.theme.ico_app_icon)
        self.timer.timeout.connect(self.timer_timeout_event)
        self.timer.setInterval(6000)
        self.timer.setSingleShot(True)
        TransCodaSettings.settings.settings_change_event.connect(self.settings_changed)
        TransCodaSettings.settings.load_ui(self, TransCoda.logger)
        self.show()
        # Executed after the show, where all dimensions are calculated
        self.progressbar.setFixedWidth(self.progressbar.width())
        self.progressbar.setVisible(False)
示例#12
0
文件: File.py 项目: ag-sd/py
 def __init__(self):
     super().__init__()
     self.file_items = []
     self.sort_column = 0
     self.sort_order = Qt.AscendingOrder
     self.columnHeaders = TransCodaSettings.get_columns()
     if not self.columnHeaders:
         self.columnHeaders = [
             Header.input_file_name, Header.input_file_size,
             Header.input_bitrate, Header.input_duration,
             Header.percent_compete, Header.input_encoder,
             Header.output_file_dir, Header.output_file_size,
             Header.compression_ratio, Header.cpu_time,
             Header.input_file_type
         ]
示例#13
0
文件: TransCodaApp.py 项目: ag-sd/py
    def validate_and_start_encoding(self, run_indices=None):
        def create_runnable(_item):
            runnable = EncoderCommand(_item)
            runnable.signals.result.connect(self.result_received_event)
            runnable.signals.status.connect(self.status_received_event)
            runnable.signals.log_message.connect(self.terminal_view.log_message)
            return runnable

        runnables = []
        is_video = False
        if run_indices is not None:
            self.main_panel.update_item_status(run_indices, EncoderStatus.WAITING)
            for index in run_indices:
                item = self.main_panel.get_items(index)
                is_video = is_video or item.is_video()
                runnables.append(create_runnable(item))
        else:
            for index in range(0, self.main_panel.row_count()):
                item = self.main_panel.get_items(index)
                self.main_panel.update_item_status([index], EncoderStatus.WAITING)
                is_video = is_video or item.is_video()
                runnables.append(create_runnable(item))

        if len(runnables) <= 0:
            self.statusBar().showMessage("Nothing to encode!")
            return

        if TransCodaSettings.sort_by_size():
            runnables.sort(key=lambda x: x.file.file_size)
        self.tool_bar.encoding_started()
        if is_video and TransCodaSettings.is_single_thread_video():
            self.begin_tasks(runnables, f"Dispatching {len(runnables)} jobs for serial encoding", len(runnables),
                             threads=1)
        else:
            self.begin_tasks(runnables, f"Dispatching {len(runnables)} jobs for encoding", len(runnables),
                             threads=TransCodaSettings.get_max_threads())
示例#14
0
文件: File.py 项目: ag-sd/py
    def update_output_file(self):
        if self.encoder is None or self.output_file_dir is None:
            return

        _, file_path = os.path.splitdrive(self.file)
        file_path, file = os.path.split(file_path)
        name, _ = os.path.splitext(file)
        output_dir = self.output_file_dir + file_path if TransCodaSettings.get_preserve_dir(
        ) else self.output_file_dir
        if self.encoder_props["extension"] == "*" or not self.is_supported():
            self.output_file = os.path.join(output_dir, file)
        elif self.encoder_props["extension"] == "":
            self.output_file = os.path.join(output_dir, name)
            TransCoda.logger.warn(
                f"Encoder props do no specify file extension. "
                f"Encoder is expected to create the output file in {self.output_file}"
            )
        else:
            self.output_file = os.path.join(
                output_dir, name + self.encoder_props["extension"])
示例#15
0
文件: TransCodaApp.py 项目: ag-sd/py
    def action_event(self, event, item_indices=None):
        if event == Action.ADD_FILE:
            file, _ = QFileDialog.getOpenFileUrl(caption="Select a File")
            if not file.isEmpty():
                self.files_changed_event(True, [file])
        elif event == Action.ADD_DIR:
            _dir = QFileDialog.getExistingDirectoryUrl(caption="Select a directory")
            if not _dir.isEmpty():
                self.files_changed_event(True, [_dir])
        elif event == Action.SETTINGS:
            TransCodaSettings.TransCodaSettings().exec()
        elif event == Action.DEL_ALL:
            self.main_panel.clear_table()
        elif event == Action.DEL_FILE:
            self.main_panel.remove_files(item_indices)
        elif event == Action.ENCODE:
            if self.executor is not None and self.executor.is_running():
                self.executor.stop_scan()
                self.statusBar().showMessage("Stop command issued. Waiting for threads to finish")
                return
            self.validate_and_start_encoding(run_indices=item_indices)
        elif event == Action.CHANGE_STATUS_SUCCESS:
            self.main_panel.update_item_status(item_indices, EncoderStatus.SUCCESS)
        elif event == Action.CHANGE_STATUS_READY:
            self.main_panel.update_item_status(item_indices, EncoderStatus.READY)
        elif event == Action.OPEN_FILE:
            self.open_paths_in_system_default(item_indices, "file")
        elif event == Action.OPEN_SOURCE:
            self.open_paths_in_system_default(item_indices, "file", func=os.path.dirname)
        elif event == Action.OPEN_DEST:
            self.open_paths_in_system_default(item_indices, "output_file", func=os.path.dirname)

        elif event == Action.ABOUT:
            with open(os.path.join(os.path.dirname(__file__), "resource/about.html"), 'r') as file:
                about_html = file.read()
            QMessageBox.about(self, TransCoda.__APP_NAME__, about_html.format(APP_NAME=TransCoda.__APP_NAME__,
                                                                              VERSION=TransCoda.__VERSION__,
                                                                              YEAR=datetime.now().year))
示例#16
0
文件: File.py 项目: ag-sd/py
 def encoder_setting_changed(self):
     self.encoder = TransCodaSettings.get_encoder_name()
     self.encoder_props = TransCodaSettings.get_encoder()
     self.update_output_file()
示例#17
0
文件: File.py 项目: ag-sd/py
 def output_dir_changed(self):
     self.output_file_dir = TransCodaSettings.get_output_dir()
     self.update_output_file()
示例#18
0
文件: TransCodaApp.py 项目: ag-sd/py
 def closeEvent(self, close_event) -> None:
     TransCoda.logger.info("Saving encode list...")
     TransCodaSettings.save_encode_list(self.main_panel.get_items())
     TransCoda.logger.info("Saving UI...")
     TransCodaSettings.settings.save_ui(self, TransCoda.logger)