Exemple #1
0
    def subtitles(
            self,
            comments: Comments) -> Generator[Tuple[str, Comment], None, None]:
        """
        Subtitle generator
        :param comments: Comments to turn into subtitles
        :return: Generator with subtitles and subtitle data
        """
        for index, comment in enumerate(comments):
            # Stat and stop timestamps. Add a millisecond for timedelta to include millisecond digits
            start = datetime.timedelta(seconds=comment.content_offset_seconds)
            stop: datetime.timedelta = start + datetime.timedelta(
                milliseconds=self.format_dictionary['duration'])

            # Format message
            message: str = Pipe(self.format_dictionary['comments']).comment(
                comment.data)

            # Subtitle variables
            # Subtract the last three milliseconds form timestamp (required by SRT)
            subtitle: dict = {
                'index': index + 1,
                'start': SRT.format_timestamp(start),
                'stop': SRT.format_timestamp(stop),
                'message': message
            }

            yield '{index}\n{start} --> {stop}\n{message}\n'.format_map(
                SafeDict(subtitle)), comment
Exemple #2
0
    def prefix(self) -> Generator[Tuple[str, None], None, None]:
        """
        SSA file header
        :return: Generator for header lines
        """
        lines: List[str] = list()

        # Script info
        lines.append('[Script Info]')
        lines.append('Title: {title}'.format_map(SafeDict(self.video.data)))
        lines.append('ScriptType: v4.00')
        lines.append('Collisions: Normal')
        lines.append('PlayResX: {resolution[x]}'.format_map(
            SafeDict(self.format_dictionary)))
        lines.append('PlayResY: {resolution[y]}'.format_map(
            SafeDict(self.format_dictionary)))
        lines.append('PlayDepth: 0')
        lines.append('Timer: 100,0000')

        # V4 Styles
        lines.append('\n[V4 Styles]')
        lines.append(self.format_dictionary['styles']['format'])
        lines.append(self.format_dictionary['styles']['values'])

        # Fonts
        lines.append('\n[Fonts]')
        lines.append(self.format_dictionary['fonts'])

        # Graphics
        lines.append('\n[Graphics]')
        lines.append(self.format_dictionary['graphics'])

        # Events
        lines.append('\n[Events]')
        lines.append(self.format_dictionary['events']['format'])

        for line in lines:
            yield line, None
Exemple #3
0
    def dialogues(
            self,
            comments: Comments) -> Generator[Tuple[str, Comments], None, None]:
        """
        Format comments as SSA dialogues
        :param comments: Comment to format
        :return: tuple(formatted comment, comment)
        """
        for comment in comments:
            start: datetime.timedelta = datetime.timedelta(
                seconds=comment.content_offset_seconds)
            end: datetime.timedelta = start + datetime.timedelta(
                milliseconds=self.format_dictionary['duration'])

            # Avoid SSA variable conflicts with Python string formatting
            # This is done by temporarily removing opening and closing curly brackets used by SSA.
            #
            # The main problem is detecting these curly brackets. We want to differentiate brackets that
            # should be used by the Python string formatter, and those used by SSA.
            #
            # Opening curly brackets for SSA can easily be found by looking for "{\", however,
            # closing curly brackets are used in the same way (just a "}") for both and requires a bit more effort.
            #
            # By incrementing a counter for opening brackets meant for Python formatting and decrementing for every
            # closing bracket meant for Python formatting, we can define every closing bracket to belong to SSA whenever
            # the counter is at zero.

            ssa_closing_brackets_indices: list = []
            open_bracket_counter: int = 0

            # Loop through every character in formatting string
            for index in range(
                    len(self.format_dictionary['comments']['format'])):
                letter: str = self.format_dictionary['comments']['format'][
                    index]

                # Check if SSA bracket first, before altering the counter.
                if letter is '}' and open_bracket_counter is 0:
                    ssa_closing_brackets_indices.append(index)
                    continue

                # Update counter
                open_bracket_counter += {
                    '{': 1,  # Bracket is opened
                    '\\': -1,  # Bracket was meant for SSA, not for Python
                    '}': -1  # Closing bracket
                }.get(letter, 0)

                # Multiple SSA commands within a curly brackets could make it negative
                # Example: {\\c&#000000&\\b1} will count 1, 0, -1, -2
                open_bracket_counter = max(0, open_bracket_counter)

            # Add a temporary special character for SSA closing curly brackets
            for index in ssa_closing_brackets_indices:
                self.format_dictionary['comments']['format'] = self.format_dictionary['comments']['format'][
                                                               :index] + SSA.SPECIAL + \
                                                               self.format_dictionary['comments']['format'][index + 1:]

            self.format_dictionary['comments'][
                'format'] = self.format_dictionary['comments'][
                    'format'].replace('{\\', SSA.OPEN).replace(
                        SSA.SPECIAL, SSA.CLOSE)

            # Format comment
            comment_text = Pipe(self.format_dictionary['comments']).comment(
                comment.data)

            # Insert opening and closing curly brackets for SSA
            comment_text = comment_text.replace(SSA.OPEN,
                                                '{\\').replace(SSA.CLOSE, '}')

            # Convert color code into SSA color code.
            comment_text = comment_text.replace('\\c&#', '\\c&H').replace(
                '\\c&H#', '\\c&H')

            dialogue: dict = {
                'start': SSA.format_timestamp(start),
                'end': SSA.format_timestamp(end),
                'comment': comment_text
            }
            dialogue.update(comment.data)

            yield self.format_dictionary['events']['dialogue'].format_map(
                SafeDict(dialogue)), comment