Пример #1
0
 def save(self, subtitle_list):
     # TODO maybe support other encodings for destination file
     # TODO handle optional coordinates (X1, X2, Y1, Y2)
     with codecs.open(self._path, 'w', encoding='utf8') as f:
         sub_counter = 0
         for subtitle in subtitle_list:
             sub_counter += 1
             sub = '{0}\r\n{1} --> {2}\r\n{3}\r\n\r\n'.format(
                 sub_counter,
                 Time.format(subtitle.start, True),
                 Time.format(subtitle.end, True),
                 subtitle.text
             )
             f.write(sub.decode('utf-8'))
Пример #2
0
 def _on_input(self, widget, text):
     try:
         millis = Time.millis_from_str(text)
     except TypeError:
         return Gtk.INPUT_ERROR
     self.set_value(millis)
     return True
Пример #3
0
 def convert_origial_to_uncut(self, path_, subtitle_loader, cuts):
     """Converts a submod-script with "timings-for" set to "original"
     to a submod-script with "timings-for" set to "uncut". So the
     submod-script can be used with other cutlists, too.
     """
     sha256 = self._hash_subtitle_file(path_).lower()
     if sha256 != self.script['subtitle']['sha256']:
         raise ValueError(_('The subtitle has a wrong checksum ("{}")!')
                          .format(sha256))
     subtitle_list = subtitle_loader(path_)
     tmp_moves_by_id = {}
     for move in self.script['move']:
         by = Time.millis_from_str(move['by'])
         for i in self._get_valid_ids(subtitle_list, move['id']):
             offset = self._get_export_offset(
                                           subtitle_list[i].start + by, cuts)
             tmp_moves_by_id[subtitle_list[i].orig_id] = (by, offset)
     self.script['move'] = []
     # Moves
     todo_move_list = self._merge_by_ids(tmp_moves_by_id)
     for id1, id2, (time_diff, offset) in todo_move_list:
         # NOTE: We do not pass  cuts here since the offset was 
         #       already calculated based on the cuts (s.a.)
         move_by = self._get_export_time(offset + time_diff)
         sign = '+' if move_by[0]!='-' else ''
         self.script['move'].append(OrderedDict([
             ('id', self._get_ids_for_script(id1, id2)),
             ('by', sign + move_by)
         ]))
     for update in self.script['update']:
         if 'start' in update:
             update['start'] = self._get_export_time(
                                 Time.millis_from_str(update['start']), cuts)
         if 'end' in update:
             update['end'] = self._get_export_time(
                                   Time.millis_from_str(update['end']), cuts)
     for add in self.script['add']:
         add['start'] = self._get_export_time(
                                    Time.millis_from_str(add['start']), cuts)
         add['end'] = self._get_export_time(
                                      Time.millis_from_str(add['end']), cuts)
     self.script['timings-for'] = 'uncut'
Пример #4
0
    def _get_next_sub(self, lines, i):
        l = lines[i].strip()
        if (self._re_id.match(l) is None):
            raise ValueError(_('Invalid id line ("{0}")').format(
                                                             l.decode('utf-8')))
        id_ = int(l)

        if (i+1 >= len(lines)):
            raise ValueError(_('Missing timestamp line'))
        l = lines[i+1].strip()
        time_match = self._re_time.match(l)
        if (time_match is None):
            raise ValueError(_('Invalid timestamp line ("{0}")').format(
                                                             l.decode('utf-8')))
        # TODO handle optional coordinates (X1, X2, Y1, Y2)
        if (time_match.group(9) is not None):
            raise NotImplementedError(
                              _('Coordinates found (currently not supported)!'))
        start = Time.millis_from_strs(time_match.group(1), time_match.group(2),
                                   time_match.group(3), time_match.group(4))
        end = Time.millis_from_strs(time_match.group(5), time_match.group(6),
                                   time_match.group(7), time_match.group(8))

        text = ''
        j = i+2
        while True:
            if (j >= len(lines)):
                raise ValueError(_('Missing text line'))
            text += lines[j] + '\r\n'
            j += 1
            if (j >= len(lines) or lines[j].strip() == ''):
                break
        
        # skip trailing empty lines
        while j<len(lines):
            if (lines[j]!=''):
                break
            j += 1

        return (j, Subtitle(start, end, text.strip(), id_))
Пример #5
0
 def _on_output(self, widget, value):
     time = Time.format(value)
     widget.set_text(time)
     return True
Пример #6
0
 def _format_time_column(self, column_num, cell, model, iter_):
     time = model.get_value(iter_, column_num)
     val = Time.format(time)
     cell.set_property('text', val)
Пример #7
0
 def _get_export_time(self, millis, cuts=None):
     if cuts is None:
         return Time.format(millis)
     offset = self._get_export_offset(millis, cuts)
     return Time.format(offset + millis)
Пример #8
0
    def run(self, path_, subtitle_loader, cuts=None):
        """Loads a SubtitleList from the subtitle file path_ using the
        given subtitle_loader function and applies the loaded Submod-
        script.
        
        subtitle_loader must be a function that accept a path as
        parameter and returns a SubtitleList.
        
        If cuts is set then the timings are adapted for these cuts so
        that the created subtitle and the cut video are in sync.
        
        The changes are always made in the following order: move,
        update, remove, add.

        NOTE: All ids specified in the Submod-script refer to the
              subtitles in the original/unchanged SubtitleList. If for
              example you specify multiple items in the "remove"-
              section you don't need to take into account that removing
              a subtitle will change the id of following subtitles.
        
        A ValueError/IndexError may be raised, for example if the
        subtitle file has a wrong checksum or if a subtitle was not
        found.
        
        Returns a SubtitleList.
        """
        # NOTE: We do not use SubtitleList's methods to modify the
        #       timestamps of subtitles. For example move_subtitle()
        #       could change the order of the subtitles so that the id's
        #       from the submod may not refer to the correct subtitle
        #       anymore. Instead we modify the subtitle's start/end
        #       values directly which will result in a SubtitleList that
        #       is not properly ordered. After moving, updating and
        #       removing subtitles we add all subtitles of the current
        #       SubtitleList to a new SubtitleList which then will take
        #       care of the correct order of the subtitles based on
        #       their timestamps. At the end we add the new subtitles
        #       from the add-section of the submod.
        sha256 = self._hash_subtitle_file(path_).lower()
        if sha256 != self.script['subtitle']['sha256']:
            raise ValueError(_('The subtitle has a wrong checksum ("{}")!')
                             .format(sha256))
        subtitle_list = subtitle_loader(path_)
        offset = 0.0
        for move in self.script['move']:
            by = Time.millis_from_str(move['by'])
            for i in self._get_valid_ids(subtitle_list, move['id']):
                if cuts is not None:
                    offset = self._get_run_offset(subtitle_list[i].start + by,
                                                  cuts)
                subtitle_list[i].start = (subtitle_list[i].start + by) - offset
                subtitle_list[i].end = (subtitle_list[i].end + by) - offset
        for update in self.script['update']:
            # Each update may contain any of end, start and text values
            # where the end/start-strings must be converted to number of
            # milliseconds.
            new_values = []
            for k, f in [('start', lambda x : self._get_run_time(
                                                Time.millis_from_str(x), cuts)),
                         ('end', lambda x : self._get_run_time(
                                                Time.millis_from_str(x), cuts)),
                         ('text', lambda x : x.encode('utf-8'))]:
                if k in update:
                    new_values.append((k, f(update[k],)))
            subtitles = self._get_subtitles_by_ids(subtitle_list, update['id'])
            for subtitle in subtitles:
                for k, v in new_values:
                    setattr(subtitle, k, v)
        # Gather ids of subs that should be removed and sort them desc.
        # The subs are removed in that order. Thus the sub with the 
        # biggest id will be removed first. If we would start with a
        # smaller id, then further ids that should be removed will point
        # to a wrong subtitle.
        to_remove = []
        for remove in self.script['remove']:
            to_remove += self._get_valid_ids(subtitle_list, remove['id'])
        for i in sorted(to_remove, reverse=True):
            subtitle_list.remove_subtitle(i)
        new_subtitle_list = SubtitleList()
        for subtitle in subtitle_list:
            new_subtitle_list.add_subtitle(subtitle)
        for add in self.script['add']:
            start = self._get_run_time(Time.millis_from_str(add['start']), cuts)
            end = self._get_run_time(Time.millis_from_str(add['end']), cuts)
            subtitle = Subtitle(start, end, add['text'].encode('utf-8'))
            new_subtitle_list.add_subtitle(subtitle)
        return new_subtitle_list