"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "ffmulticonverter/progress.py" between
ffmulticonverter-1.7.2.tar.gz and ffmulticonverter-1.8.0.tar.gz

About: FF Multi Converter is a graphical application which enables you to convert audio, video, image and document files between all popular formats, using and combining other programs.

progress.py  (ffmulticonverter-1.7.2):progress.py  (ffmulticonverter-1.8.0)
# Copyright (C) 2011-2015 Ilias Stamatis <stamatis.iliass@gmail.com> # Copyright (C) 2011-2016 Ilias Stamatis <stamatis.iliass@gmail.com>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
skipping to change at line 25 skipping to change at line 25
import os import os
import re import re
import io import io
import signal import signal
import threading import threading
import subprocess import subprocess
import shlex import shlex
import logging import logging
from PyQt4.QtCore import pyqtSignal, QTimer from PyQt5.QtCore import pyqtSignal, QTimer
from PyQt4.QtGui import ( from PyQt5.QtGui import QTextCursor
from PyQt5.QtWidgets import (
QApplication, QDialog, QFrame, QLabel, QPushButton, QProgressBar, QApplication, QDialog, QFrame, QLabel, QPushButton, QProgressBar,
QMessageBox, QTextEdit, QCommandLinkButton, QTextCursor, QSizePolicy QMessageBox, QTextEdit, QCommandLinkButton, QSizePolicy, QCheckBox
) )
from ffmulticonverter import utils from ffmulticonverter import utils
class Progress(QDialog): class Progress(QDialog):
file_converted_signal = pyqtSignal() file_converted_signal = pyqtSignal()
refr_bars_signal = pyqtSignal(int)
update_text_edit_signal = pyqtSignal(str) update_text_edit_signal = pyqtSignal(str)
def __init__(self, files, tab, delete, parent, test=False): def __init__(self, files, tab, delete, parent, test=False):
""" """
Keyword arguments: Keyword arguments:
files -- list with dicts containing file names files -- list with dicts containing file names
tab -- instanseof AudioVideoTab, ImageTab or DocumentTab tab -- instanseof AudioVideoTab, ImageTab or DocumentTab
indicating currently active tab indicating currently active tab
delete -- boolean that shows if files must removed after conversion delete -- boolean that shows if files must removed after conversion
parent -- parent widget parent -- parent widget
skipping to change at line 64 skipping to change at line 64
""" """
super(Progress, self).__init__(parent) super(Progress, self).__init__(parent)
self.parent = parent self.parent = parent
self.files = files self.files = files
self.num_total_files = len(self.files) self.num_total_files = len(self.files)
self.tab = tab self.tab = tab
self.delete = delete self.delete = delete
if not test: if not test:
self._type = tab.name self._type = tab.name
self.step = int(100 / len(files))
self.ok = 0 self.ok = 0
self.error = 0 self.error = 0
self.running = True self.running = True
self.nowQL = QLabel(self.tr('In progress: ')) self.nowQL = QLabel(self.tr('In progress: '))
totalQL = QLabel(self.tr('Total:'))
self.nowQPBar = QProgressBar() self.nowQPBar = QProgressBar()
self.nowQPBar.setValue(0) self.nowQPBar.setValue(0)
self.totalQPBar = QProgressBar() self.shutdownQCB = QCheckBox(self.tr('Shutdown after conversion'))
self.totalQPBar.setValue(0)
self.cancelQPB = QPushButton(self.tr('Cancel')) self.cancelQPB = QPushButton(self.tr('Cancel'))
detailsQPB = QCommandLinkButton(self.tr('Details')) detailsQPB = QCommandLinkButton(self.tr('Details'))
detailsQPB.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) detailsQPB.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
detailsQPB.setCheckable(True) detailsQPB.setCheckable(True)
detailsQPB.setMaximumWidth(113) detailsQPB.setMaximumWidth(113)
line = QFrame() line = QFrame()
line.setFrameShape(QFrame.HLine) line.setFrameShape(QFrame.HLine)
line.setFrameShadow(QFrame.Sunken) line.setFrameShadow(QFrame.Sunken)
self.outputQTE = QTextEdit() self.outputQTE = QTextEdit()
self.outputQTE.setReadOnly(True) self.outputQTE.setReadOnly(True)
self.frame = QFrame() self.frame = QFrame()
frame_layout = utils.add_to_layout('h', self.outputQTE) frame_layout = utils.add_to_layout('h', self.outputQTE)
self.frame.setLayout(frame_layout) self.frame.setLayout(frame_layout)
self.frame.hide() self.frame.hide()
hlayout = utils.add_to_layout('h', None, self.nowQL, None) hlayout1 = utils.add_to_layout('h', None, self.nowQL, None)
hlayout2 = utils.add_to_layout('h', None, totalQL, None) hlayout2 = utils.add_to_layout('h', detailsQPB, line)
hlayout3 = utils.add_to_layout('h', detailsQPB, line) hlayout3 = utils.add_to_layout('h', self.frame)
hlayout4 = utils.add_to_layout('h', self.frame) hlayout4 = utils.add_to_layout('h', None, self.cancelQPB)
hlayout5 = utils.add_to_layout('h', None, self.cancelQPB)
vlayout = utils.add_to_layout( vlayout = utils.add_to_layout(
'v', hlayout, self.nowQPBar, hlayout2, self.totalQPBar, None, 'v', hlayout1, self.nowQPBar, hlayout2, hlayout3,
hlayout3, hlayout4, hlayout5 self.shutdownQCB, hlayout4
) )
self.setLayout(vlayout) self.setLayout(vlayout)
detailsQPB.toggled.connect(self.resize_dialog) detailsQPB.toggled.connect(self.resize_dialog)
detailsQPB.toggled.connect(self.frame.setVisible) detailsQPB.toggled.connect(self.frame.setVisible)
self.cancelQPB.clicked.connect(self.reject) self.cancelQPB.clicked.connect(self.reject)
self.file_converted_signal.connect(self.next_file) self.file_converted_signal.connect(self.next_file)
self.refr_bars_signal.connect(self.refresh_progress_bars)
self.update_text_edit_signal.connect(self.update_text_edit) self.update_text_edit_signal.connect(self.update_text_edit)
self.resize(484, 200) self.resize(484, 190)
self.setWindowTitle('FF Multi Converter - ' + self.tr('Conversion')) self.setWindowTitle('FF Multi Converter - ' + self.tr('Conversion'))
if not test: if not test:
self.get_data() # should be first and not in QTimer.singleShot() self.get_data() # should be first and not in QTimer.singleShot()
QTimer.singleShot(0, self.manage_conversions) QTimer.singleShot(0, self.manage_conversions)
def get_data(self): def get_data(self):
"""Collect conversion data from parents' widgets.""" """Collect conversion data from parents' widgets."""
if self._type == 'AudioVideo': if self._type == 'AudioVideo':
self.cmd = self.tab.commandQLE.text() self.cmd = self.tab.commandQLE.text()
skipping to change at line 140 skipping to change at line 135
self.imgcmd += ' -trim +repage' self.imgcmd += ' -trim +repage'
rotate = self.tab.rotateQLE.text().strip() rotate = self.tab.rotateQLE.text().strip()
if rotate: if rotate:
self.imgcmd += ' -rotate {0}'.format(rotate) self.imgcmd += ' -rotate {0}'.format(rotate)
if self.tab.vflipQChB.isChecked(): if self.tab.vflipQChB.isChecked():
self.imgcmd += ' -flip' self.imgcmd += ' -flip'
if self.tab.hflipQChB.isChecked(): if self.tab.hflipQChB.isChecked():
self.imgcmd += ' -flop' self.imgcmd += ' -flop'
def resize_dialog(self): def resize_dialog(self):
"""Resize dialog.""" """Resize dialog"""
height = 200 if self.frame.isVisible() else 366 height = 190 if self.frame.isVisible() else 450
self.setMinimumSize(484, height) self.setMinimumSize(484, height)
self.resize(484, height) self.resize(484, height)
def update_text_edit(self, txt): def update_text_edit(self, txt):
"""Append txt to the end of current self.outputQTE's text.""" """Append txt to the end of current self.outputQTE's text."""
current = self.outputQTE.toPlainText() current = self.outputQTE.toPlainText()
self.outputQTE.setText(current+txt) self.outputQTE.setText(current+txt)
self.outputQTE.moveCursor(QTextCursor.End) self.outputQTE.moveCursor(QTextCursor.End)
def refresh_progress_bars(self, now_percent):
"""Refresh the values of self.nowQPBar and self.totalQPBar."""
total_percent = int(((now_percent * self.step) / 100) + self.min_value)
if now_percent > self.nowQPBar.value() and not (now_percent > 100):
self.nowQPBar.setValue(now_percent)
if (total_percent > self.totalQPBar.value() and
not (total_percent > self.max_value)):
self.totalQPBar.setValue(total_percent)
def manage_conversions(self): def manage_conversions(self):
""" """
Check whether all files have been converted. Check whether all files have been converted.
If not, it will allow convert_a_file() to convert the next file. If not, it will allow convert_a_file() to convert the next file.
""" """
if not self.running: if not self.running:
return return
if not self.files: if not self.files:
self.totalQPBar.setValue(100)
if self.totalQPBar.value() >= 100:
sum_files = self.ok + self.error sum_files = self.ok + self.error
msg = QMessageBox(self) msg = QMessageBox(self)
msg.setStandardButtons(QMessageBox.Ok) msg.setStandardButtons(QMessageBox.Ok)
msg.setWindowTitle(self.tr("Report")) msg.setWindowTitle(self.tr("Report"))
msg.setText(self.tr("Converted: {0}/{1}".format(self.ok,sum_files))) msg.setText(self.tr("Converted: {0}/{1}".format(self.ok,sum_files)))
msg.setModal(False) msg.setModal(False)
msg.show() msg.show()
self.cancelQPB.setText(self.tr("Close")) self.cancelQPB.setText(self.tr("Close"))
if self.shutdownQCB.isChecked():
if utils.is_installed('systemctl'):
subprocess.call(shlex.split('systemctl poweroff'))
else:
subprocess.call(shlex.split('shutdown -h now'))
else: else:
self.convert_a_file() self.convert_a_file()
def next_file(self): def next_file(self):
""" """
Update progress bars values, remove converted file from self.files Update progress bar value, remove converted file from self.files
and call manage_conversions() to continue the process. and call manage_conversions() to continue the process.
""" """
self.totalQPBar.setValue(self.max_value)
self.nowQPBar.setValue(100) self.nowQPBar.setValue(100)
QApplication.processEvents() QApplication.processEvents()
self.files.pop(0) self.files.pop(0)
self.manage_conversions() self.manage_conversions()
def reject(self): def reject(self):
""" """
Use standard dialog to ask whether procedure must stop or not. Use standard dialog to ask whether procedure must stop or not.
Use the SIGSTOP to stop the conversion process while waiting for user Use the SIGSTOP to stop the conversion process while waiting for user
to respond and SIGCONT or kill depending on user's answer. to respond and SIGCONT or kill depending on user's answer.
skipping to change at line 243 skipping to change at line 231
from_file = list(self.files[0].keys())[0] from_file = list(self.files[0].keys())[0]
to_file = list(self.files[0].values())[0] to_file = list(self.files[0].values())[0]
text = os.path.basename(from_file[1:-1]) text = os.path.basename(from_file[1:-1])
num_file = self.num_total_files - len(self.files) + 1 num_file = self.num_total_files - len(self.files) + 1
text += ' ({0}/{1})'.format(num_file, self.num_total_files) text += ' ({0}/{1})'.format(num_file, self.num_total_files)
self.nowQL.setText(self.tr('In progress:') + ' ' + text) self.nowQL.setText(self.tr('In progress:') + ' ' + text)
self.nowQPBar.setValue(0) self.nowQPBar.setValue(0)
self.min_value = self.totalQPBar.value()
self.max_value = self.min_value + self.step
if not os.path.exists(from_file[1:-1]): if not os.path.exists(from_file[1:-1]):
self.error += 1 self.error += 1
self.file_converted_signal.emit() self.file_converted_signal.emit()
return return
def convert(): def convert():
if self._type == 'AudioVideo': if self._type == 'AudioVideo':
conv_func = self.convert_video conv_func = self.convert_video
params = (from_file, to_file, self.cmd) params = (from_file, to_file, self.cmd)
elif self._type == 'Images': elif self._type == 'Images':
skipping to change at line 283 skipping to change at line 268
self.file_converted_signal.emit() self.file_converted_signal.emit()
self.thread = threading.Thread(target=convert) self.thread = threading.Thread(target=convert)
self.thread.start() self.thread.start()
def convert_video(self, from_file, to_file, command): def convert_video(self, from_file, to_file, command):
""" """
Create the ffmpeg command and execute it in a new process using the Create the ffmpeg command and execute it in a new process using the
subprocess module. While the process is alive, parse ffmpeg output, subprocess module. While the process is alive, parse ffmpeg output,
estimate conversion progress using video's duration. estimate conversion progress using video's duration.
With the result, emit the corresponding signal in order progressbars With the result, emit the corresponding signal in order progress bar
to be updated. Also emit regularly the corresponding signal in order to be updated. Also emit regularly the corresponding signal in order
an outputQTE to be updated with ffmpeg's output. Finally, save log an outputQTE to be updated with ffmpeg's output. Finally, save log
information. information.
Return True if conversion succeed, else False. Return True if conversion succeed, else False.
""" """
# note: from_file and to_file names are inside quotation marks # note: from_file and to_file names are inside quotation marks
convert_cmd = '{0} -y -i {1} {2} {3}'.format( convert_cmd = '{0} -y -i {1} {2} {3}'.format(
self.parent.vidconverter, from_file, command, to_file) self.parent.ffmpeg_path, from_file, command, to_file)
self.update_text_edit_signal.emit(convert_cmd + '\n') self.update_text_edit_signal.emit(convert_cmd + '\n')
self.process = subprocess.Popen( self.process = subprocess.Popen(
shlex.split(convert_cmd), shlex.split(convert_cmd),
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
stdout=subprocess.PIPE stdout=subprocess.PIPE
) )
final_output = myline = '' final_output = myline = ''
reader = io.TextIOWrapper(self.process.stdout, encoding='utf8') reader = io.TextIOWrapper(self.process.stdout, encoding='utf8')
skipping to change at line 321 skipping to change at line 306
total = utils.duration_in_seconds(m.group(1)) total = utils.duration_in_seconds(m.group(1))
n = re.search("time=([0-9:]+)", myline) n = re.search("time=([0-9:]+)", myline)
# time can be of format 'time=hh:mm:ss.ts' or 'time=ss.ts' # time can be of format 'time=hh:mm:ss.ts' or 'time=ss.ts'
# depending on ffmpeg version # depending on ffmpeg version
if n: if n:
time = n.group(1) time = n.group(1)
if ':' in time: if ':' in time:
time = utils.duration_in_seconds(time) time = utils.duration_in_seconds(time)
now_sec = int(float(time)) now_sec = int(float(time))
try: try:
self.refr_bars_signal.emit(100 * now_sec / total) self.nowQPBar.setValue(100 * now_sec / total)
except (UnboundLocalError, ZeroDivisionError): except (UnboundLocalError, ZeroDivisionError):
pass pass
self.update_text_edit_signal.emit(myline) self.update_text_edit_signal.emit(myline)
final_output += myline final_output += myline
myline = '' myline = ''
self.update_text_edit_signal.emit('\n\n') self.update_text_edit_signal.emit('\n\n')
return_code = self.process.poll() return_code = self.process.poll()
log_data = { log_data = {
 End of changes. 21 change blocks. 
40 lines changed or deleted 25 lines changed or added

Home  |  About  |  All  |  Newest  |  Fossies Dox  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTPS