"Fossies" - the Fresh Open Source Software Archive

Member "ffmulticonverter-1.8.0/ffmulticonverter/utils.py" (22 Jun 2016, 12735 Bytes) of package /linux/privat/ffmulticonverter-1.8.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "utils.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.7.2_vs_1.8.0.

    1 # Copyright (C) 2011-2016 Ilias Stamatis <stamatis.iliass@gmail.com>
    2 #
    3 # This program is free software: you can redistribute it and/or modify
    4 # it under the terms of the GNU General Public License as published by
    5 # the Free Software Foundation, either version 3 of the License, or
    6 # (at your option) any later version.
    7 #
    8 # This program is distributed in the hope that it will be useful,
    9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   11 # GNU General Public License for more details.
   12 #
   13 # You should have received a copy of the GNU General Public License
   14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
   15 
   16 """
   17 Various useful functions.
   18 """
   19 
   20 import os
   21 import re
   22 import sys
   23 import shlex
   24 import subprocess
   25 import time
   26 
   27 from PyQt5.QtCore import pyqtSignal, QSize, Qt
   28 from PyQt5.QtWidgets import (
   29         QAction, QLayout, QLineEdit, QListWidget, QListWidgetItem, QMenu,
   30         QSpacerItem, QWidget, QHBoxLayout, QVBoxLayout, QGridLayout
   31         )
   32 
   33 
   34 def duration_in_seconds(duration):
   35     """
   36     Return the number of seconds of duration, an integer.
   37     Duration is a string of type hh:mm:ss.ts
   38     """
   39     duration = duration.split('.')[0] # get rid of milliseconds
   40     hours, mins, secs = [int(i) for i in duration.split(':')]
   41     return secs + (hours * 3600) + (mins * 60)
   42 
   43 def is_installed(program):
   44     """
   45     If program is a program name, returns the absolute path to this program if
   46     included in the PATH enviromental variable, else empty string.
   47 
   48     If program is an absolute path, returns the path if it's executable, else
   49     empty sring.
   50     """
   51     program = os.path.expanduser(program)
   52     for path in os.getenv('PATH').split(os.pathsep):
   53         fpath = os.path.join(path, program)
   54         if os.path.isfile(fpath) and os.access(fpath, os.X_OK):
   55             return fpath
   56     return ''
   57 
   58 def start_office_listener():
   59     """
   60     Start a openoffice/libreoffice listener.
   61     We need an open office listener in order to make convertions with unoconv.
   62     """
   63     # note: we cannot kill the listener with p.kill() as it is a spawned process
   64     # the office listener remains open even after program's termination
   65     p = subprocess.Popen(shlex.split("unoconv --listener"))
   66     while p.poll() is not None:
   67         time.sleep(0.1)
   68     time.sleep(1) # wait for listener to setup correctly
   69 
   70 def find_presets_file(fname, lookup_dirs, lookup_virtenv):
   71     """
   72     The default presets.xml could be stored in different locations during
   73     the installation depending on different Linux distributions.
   74     Search for this file on each possible directory to which user
   75     specific data files could be stored.
   76 
   77     Keyword arguments:
   78     fname          -- file name
   79     lookup_dirs    -- list of the directories to search for fname
   80     lookup_virtent -- directory to search for fname in virtualenv
   81 
   82     Return the path of the file if found, else an empty string.
   83     """
   84     possible_dirs = os.environ.get(
   85             "XDG_DATA_DIRS", ":".join(lookup_dirs)
   86             ).split(":")
   87     # for virtualenv installations
   88     posdir = os.path.realpath(
   89             os.path.join(os.path.dirname(sys.argv[0]), '..', lookup_virtenv))
   90     if not posdir in possible_dirs:
   91         possible_dirs.append(posdir)
   92 
   93     for _dir in possible_dirs:
   94         _file = os.path.join(_dir, 'ffmulticonverter/' + fname)
   95         if os.path.exists(_file):
   96             return _file
   97 
   98     # when program is not installed or running from test_dialogs.py
   99     return os.path.dirname(os.path.realpath(__file__)) + '/../share/' + fname
  100 
  101 def create_paths_list(
  102         files_list, ext_to, prefix, suffix, output, orig_dir,
  103         overwrite_existing
  104         ):
  105     """
  106     Create and return a list with dicts.
  107     Each dict will have only one key and one corresponding value.
  108     Key will be a file to be converted and it's value will be the name
  109     of the new converted file.
  110 
  111     Example list:
  112     [{"/foo/bar.png" : "/foo/bar.bmp"}, {"/f/bar2.png" : "/f/bar2.bmp"}]
  113 
  114     Keyword arguments:
  115     files_list -- list with files to be converted
  116     ext_to     -- the extension to which each file must be converted to
  117     prefix     -- string that will be added as a prefix to all filenames
  118     suffix     -- string that will be added as a suffix to all filenames
  119     output     -- the output folder
  120     orig_dir   -- if True, each file will be saved at its original directory
  121                   else, files will be saved at output
  122     overwrite_existing -- if False, a '~' will be added as prefix to
  123                           filenames
  124     """
  125     assert ext_to.startswith('.'), 'ext_to must start with a dot (.)'
  126 
  127     conversion_list = []
  128     dummy = []
  129 
  130     for _file in files_list:
  131         _dir, name = os.path.split(_file)
  132         y = prefix + os.path.splitext(name)[0] + suffix + ext_to
  133 
  134         if orig_dir:
  135             y = _dir + '/' + y
  136         else:
  137             y = output + '/' + y
  138 
  139         if not overwrite_existing:
  140             while os.path.exists(y) or y in dummy:
  141                 _dir2, _name2 = os.path.split(y)
  142                 y = _dir2 + '/~' + _name2
  143 
  144         dummy.append(y)
  145         # Add quotations to paths in order to avoid error in special
  146         # cases such as spaces or special characters.
  147         _file = '"' + _file + '"'
  148         y = '"' + y + '"'
  149 
  150         _dict = {}
  151         _dict[_file] = y
  152         conversion_list.append(_dict)
  153 
  154     return conversion_list
  155 
  156 def update_cmdline_text(command, _filter, regex, add, gindex1, gindex2):
  157     """
  158     Update and return the command line text by adding, removing or edditing a
  159     ffmpeg filter based on the given regular expression.
  160 
  161     Keyword arguments:
  162     command  -- initial command text (string)
  163     _filter  -- ffmpeg filter to add or edit in command (string)
  164     regex    -- regex to search in command
  165     add      -- if True, add filter to command, else filter must be removed
  166     gindex1  -- group index of the first group before filter group in regex
  167     gindex2  -- group index of the first group after filter group in regex
  168     """
  169     regex2 = r'(-vf "[^"]*)"'
  170     regex3 = r'-vf +([^ ]+)'
  171 
  172     search = re.search(regex, command)
  173     if search:
  174         if add:
  175             command = re.sub(
  176                     regex,
  177                     r'\{0}{1}\{2}'.format(gindex1+1, _filter, gindex2+1),
  178                     command
  179                     )
  180         else:
  181             group1 = search.groups()[gindex1].strip()
  182             group2 = search.groups()[gindex2].strip()
  183             if group1 and group2:
  184                 # the filter is between 2 other filters
  185                 # remove it and leave a comma
  186                 command = re.sub(regex, ',', command)
  187             else:
  188                 # remove filter
  189                 command = re.sub(regex, _filter, command)
  190                 # add a space between -vf and filter if needed
  191                 command = re.sub(r'-vf([^ ])', r'-vf \1', command)
  192                 if not group1 and not group2:
  193                     # remove -vf option
  194                     command = re.sub(r'-vf *("\s*"){0,1}', '', command)
  195     elif re.search(regex2, command):
  196         command = re.sub(regex2, r'\1,{0}"'.format(_filter), command)
  197     elif re.search(regex3, command):
  198         command = re.sub(regex3, r'-vf "\1,{0}"'.format(_filter), command)
  199     elif _filter:
  200         command += ' -vf "' + _filter + '"'
  201 
  202     return re.sub(' +', ' ', command).strip()
  203 
  204 
  205 #######################################################################
  206 # Useful pyqt-related functions to automate some parts of ui creation.
  207 #######################################################################
  208 
  209 def add_to_layout(layout, *items):
  210     """Add items to QVBox and QHBox layouts easily.
  211 
  212     Keyword arguments:
  213     layout -- a layout oject (QVBoxLayout or QHBoxLayout) or a string
  214               if "v" or "h" create a QVBox or QHBox respectively
  215     *items -- list with items to be added
  216     """
  217     if isinstance(layout, str):
  218         if layout == "v":
  219             layout = QVBoxLayout()
  220         elif layout == "h":
  221             layout = QHBoxLayout()
  222         else:
  223             raise TypeError("Invalid layout!")
  224 
  225     for item in items:
  226         if isinstance(item, QWidget):
  227             layout.addWidget(item)
  228         elif isinstance(item, QLayout):
  229             layout.addLayout(item)
  230         elif isinstance(item, QSpacerItem):
  231             layout.addItem(item)
  232         elif item is None:
  233             layout.addStretch()
  234         else:
  235             raise TypeError("Argument of wrong type!")
  236     return layout
  237 
  238 def add_to_grid(*items):
  239     """Add items to a QGrid layout easily.
  240 
  241     Keyword arguments:
  242     *items -- list with lists of items to be added.
  243               items in the same list will be added to the same line of grid.
  244     """
  245     layout = QGridLayout()
  246     # for now it adds only 1 item per cell.
  247     for x, _list in enumerate(items):
  248         for y, item in enumerate(_list):
  249             if isinstance(item, QWidget):
  250                 layout.addWidget(item, x, y)
  251             elif isinstance(item, QLayout):
  252                 layout.addLayout(item, x, y)
  253             elif isinstance(item, QSpacerItem):
  254                 layout.addItem(item, x, y)
  255             elif item is None:
  256                 pass
  257             else:
  258                 raise TypeError("Argument of wrong type!")
  259     return layout
  260 
  261 def create_action(parent, text, shortcut=None, icon=None, tip=None,
  262                   triggered=None, toggled=None, context=Qt.WindowShortcut):
  263     """Create a QAction with the given attributes."""
  264     action = QAction(text, parent)
  265     if triggered is not None:
  266         action.triggered.connect(triggered)
  267     if toggled is not None:
  268         action.toggled.connect(toggled)
  269         action.setCheckable(True)
  270     if icon is not None:
  271         action.setIcon( icon )
  272     if shortcut is not None:
  273         action.setShortcut(shortcut)
  274     if tip is not None:
  275         action.setToolTip(tip)
  276         action.setStatusTip(tip)
  277     action.setShortcutContext(context)
  278     return action
  279 
  280 def add_actions(target, actions, insert_before=None):
  281     """Add actions to menu.
  282 
  283     Keyword arguments:
  284     target -- menu to add action
  285     actions -- list with actions to add
  286     """
  287     previous_action = None
  288     target_actions = list(target.actions())
  289     if target_actions:
  290         previous_action = target_actions[-1]
  291         if previous_action.isSeparator():
  292             previous_action = None
  293     for action in actions:
  294         if (action is None) and (previous_action is not None):
  295             if insert_before is None:
  296                 target.addSeparator()
  297             else:
  298                 target.insertSeparator(insert_before)
  299         elif isinstance(action, QMenu):
  300             if insert_before is None:
  301                 target.addMenu(action)
  302             else:
  303                 target.insertMenu(insert_before, action)
  304         elif isinstance(action, QAction):
  305             if insert_before is None:
  306                 target.addAction(action)
  307             else:
  308                 target.insertAction(insert_before, action)
  309         previous_action = action
  310 
  311 def create_LineEdit(maxsize, validator, maxlength):
  312     """Create a lineEdit with the given attributes.
  313 
  314     Keyword arguments:
  315     maxsize -- maximum size
  316     validator -- a QValidator
  317     maxlength - maximum length
  318 
  319     Returns: QLineEdit
  320     """
  321     lineEdit = QLineEdit()
  322     if maxsize is not None:
  323         lineEdit.setMaximumSize(QSize(maxsize[0], maxsize[1]))
  324     if validator is not None:
  325         lineEdit.setValidator(validator)
  326     if maxlength is not None:
  327         lineEdit.setMaxLength(maxlength)
  328     return lineEdit
  329 
  330 
  331 ######################
  332 # Custom pyqt widgets
  333 ######################
  334 
  335 class XmlListItem(QListWidgetItem):
  336     def __init__(self, text, xml_element, parent=None):
  337         super(XmlListItem, self).__init__(text, parent)
  338         self.xml_element = xml_element
  339 
  340 
  341 class FilesList(QListWidget):
  342     dropped = pyqtSignal(list)
  343 
  344     def __init__(self, parent=None):
  345         super(FilesList, self).__init__(parent)
  346         self.setAcceptDrops(True)
  347 
  348     def dragEnterEvent(self, event):
  349         if event.mimeData().hasUrls:
  350             event.accept()
  351         else:
  352             event.ignore()
  353 
  354     def dragMoveEvent(self, event):
  355         if event.mimeData().hasUrls:
  356             event.setDropAction(Qt.CopyAction)
  357             event.accept()
  358         else:
  359             event.ignore()
  360 
  361     def dropEvent(self, event):
  362         if event.mimeData().hasUrls:
  363             event.setDropAction(Qt.CopyAction)
  364             event.accept()
  365             links = []
  366             for url in event.mimeData().urls():
  367                 links.append(url.toLocalFile())
  368             self.dropped.emit(links)
  369         else:
  370             event.ignore()